Home | History | Annotate | Line # | Download | only in warp
      1 /* Header: /usr/src/games/warp/RCS/intrp.c,v 1.2 87/07/03 00:56:37 games Exp
      2  *
      3  * Revision 7.0.1.2  86/12/12  16:59:04  lwall
      4  * Baseline for net release.
      5  *
      6  * Revision 7.0.1.1  86/10/16  10:51:43  lwall
      7  * Added Damage.  Fixed random bugs.
      8  *
      9  * Revision 7.0  86/10/08  15:12:19  lwall
     10  * Split into separate files.  Added amoebas and pirates.
     11  *
     12  */
     13 
     14 #include "EXTERN.h"
     15 #include "warp.h"
     16 #include "sig.h"
     17 #include "util.h"
     18 #include "term.h"
     19 #include "INTERN.h"
     20 #include "intrp.h"
     21 
     22 /* name of this host */
     23     char *hostname;
     24 
     25 #ifdef TILDENAME
     26 static char *tildename = NULL;
     27 static char *tildedir = NULL;
     28 #endif
     29 
     30 static char *getrealname(uid_t);
     31 #ifdef CONDSUB
     32 static char *skipinterp(const char *, const char *);
     33 #endif
     34 
     35 __dead static void abort_interp(void);
     36 
     37 void
     38 intrp_init(char *tcbuf)
     39 {
     40     /* get environmental stuff */
     41 
     42     /* get home directory */
     43 
     44     homedir = getenv("HOME");
     45     if (homedir == NULL)
     46 	homedir = getenv("LOGDIR");
     47 
     48     dotdir = getval("DOTDIR",homedir);
     49 
     50     /* get login name */
     51 
     52     logname = getenv("USER");
     53     if (logname == NULL)
     54 	logname = getenv("LOGNAME");
     55 #ifdef GETLOGIN
     56     if (logname == NULL)
     57 	logname = savestr(getlogin());
     58 #endif
     59 
     60     /* get the real name of the person (%N) */
     61     /* Must be done after logname is read in because BERKNAMES uses that */
     62 
     63     strcpy(tcbuf,getrealname(getuid()));
     64     realname = savestr(tcbuf);
     65 
     66     /* name of this host (%H) */
     67 
     68     gethostname(buf,sizeof buf);
     69     hostname = savestr(buf);
     70     if (strchr(hostname,'.'))
     71 	hostname = savestr(hostname);
     72     else {
     73 	char hname[128];
     74 
     75 	strcpy(hname,hostname);
     76 	strcat(hname,MYDOMAIN);
     77 	hostname=savestr(hname);
     78     }
     79     warplib = savestr(filexp(WARPLIB));
     80 
     81     if (scorespec)			/* that getwd below takes ~1/3 sec. */
     82 	return;				/* and we do not need it for -s */
     83     (void) getcwd(tcbuf, sizeof(tcbuf));/* find working directory name */
     84     origdir = savestr(tcbuf);		/* and remember it */
     85 }
     86 
     87 /* expand filename via %, ~, and $ interpretation */
     88 /* returns pointer to static area */
     89 /* Note that there is a 1-deep cache of ~name interpretation */
     90 
     91 char *
     92 filexp(const char *s)
     93 {
     94     static char filename[CBUFLEN];
     95     char scrbuf[CBUFLEN];
     96     char *d;
     97 
     98 #ifdef DEBUGGING
     99     if (debug & DEB_FILEXP)
    100 	printf("< %s\r\n",s);
    101 #endif
    102     interp(filename, (sizeof filename), s);			/* interpret any % escapes */
    103 #ifdef DEBUGGING
    104     if (debug & DEB_FILEXP)
    105 	printf("%% %s\r\n",filename);
    106 #endif
    107     s = filename;
    108     if (*s == '~') {	/* does destination start with ~? */
    109 	if (!*(++s) || *s == '/') {
    110 	    snprintf(scrbuf, sizeof(scrbuf), "%s%s",homedir,s);
    111 				/* swap $HOME for it */
    112 #ifdef DEBUGGING
    113     if (debug & DEB_FILEXP)
    114 	printf("~ %s\r\n",scrbuf);
    115 #endif
    116 	    strcpy(filename,scrbuf);
    117 	}
    118 	else {
    119 #ifdef TILDENAME
    120 	    for (d=scrbuf; isalnum((unsigned char)*s); s++,d++)
    121 		*d = *s;
    122 	    *d = '\0';
    123 	    if (tildedir && strEQ(tildename,scrbuf)) {
    124 		strcpy(scrbuf,tildedir);
    125 		strcat(scrbuf, s);
    126 		strcpy(filename, scrbuf);
    127 #ifdef DEBUGGING
    128 		if (debug & DEB_FILEXP)
    129 		    printf("r %s %s\r\n",tildename,tildedir);
    130 #endif
    131 	    }
    132 	    else {
    133 		if (tildename) {
    134 		    free(tildename);
    135 		    free(tildedir);
    136 		}
    137 		tildedir = NULL;
    138 		tildename = savestr(scrbuf);
    139 		{
    140 		    struct passwd *pwd = getpwnam(tildename);
    141 
    142 		    snprintf(scrbuf, sizeof(scrbuf), "%s%s",pwd->pw_dir,s);
    143 		    tildedir = savestr(pwd->pw_dir);
    144 		    strcpy(filename,scrbuf);
    145 		    endpwent();
    146 		}
    147 	    }
    148 #else /* !TILDENAME */
    149 #ifdef VERBOSE
    150 	    IF(verbose)
    151 		fputs("~loginname not implemented.\r\n",stdout);
    152 	    ELSE
    153 #endif
    154 #ifdef TERSE
    155 		fputs("~login not impl.\r\n",stdout);
    156 #endif
    157 #endif
    158 	}
    159     }
    160     else if (*s == '$') {	/* starts with some env variable? */
    161 	d = scrbuf;
    162 	*d++ = '%';
    163 	if (s[1] == '{')
    164 	    strcpy(d,s+2);
    165 	else {
    166 	    *d++ = '{';
    167 	    for (s++; isalnum((unsigned char)*s); s++) *d++ = *s;
    168 				/* skip over token */
    169 	    *d++ = '}';
    170 	    strcpy(d,s);
    171 	}
    172 #ifdef DEBUGGING
    173 	if (debug & DEB_FILEXP)
    174 	    printf("$ %s\r\n",scrbuf);
    175 #endif
    176 	interp(filename, (sizeof filename), scrbuf);
    177 					/* this might do some extra '%'s but */
    178 					/* that is how the Mercedes Benz */
    179     }
    180 #ifdef DEBUGGING
    181     if (debug & DEB_FILEXP)
    182 	printf("> %s\r\n",filename);
    183 #endif
    184     return filename;
    185 }
    186 
    187 #ifdef CONDSUB
    188 /* skip interpolations */
    189 
    190 static char *
    191 skipinterp(const char *pattern, const char *stoppers)
    192 {
    193 
    194     while (*pattern && (!stoppers || !strchr(stoppers,*pattern))) {
    195 #ifdef DEBUGGING
    196 	if (debug & 8)
    197 	    printf("skipinterp till %s at %s\r\n",stoppers?stoppers:"",pattern);
    198 #endif
    199 	if (*pattern == '%' && pattern[1]) {
    200 	    switch (*++pattern) {
    201 	    case '{':
    202 		for (pattern++; *pattern && *pattern != '}'; pattern++)
    203 		    if (*pattern == '\\')
    204 			pattern++;
    205 		break;
    206 #ifdef CONDSUB
    207 	    case '(': {
    208 		pattern = skipinterp(pattern+1,"!=");
    209 		if (!*pattern)
    210 		    goto getout;
    211 		for (pattern++; *pattern && *pattern != '?'; pattern++)
    212 		    if (*pattern == '\\')
    213 			pattern++;
    214 		if (!*pattern)
    215 		    goto getout;
    216 		pattern = skipinterp(pattern+1,":)");
    217 		if (*pattern == ':')
    218 		    pattern = skipinterp(pattern+1,")");
    219 		break;
    220 	    }
    221 #endif
    222 #ifdef BACKTICK
    223 	    case '`': {
    224 		pattern = skipinterp(pattern+1,"`");
    225 		break;
    226 	    }
    227 #endif
    228 #ifdef PROMPTTTY
    229 	    case '"':
    230 		pattern = skipinterp(pattern+1,"\"");
    231 		break;
    232 #endif
    233 	    default:
    234 		break;
    235 	    }
    236 	    pattern++;
    237 	}
    238 	else {
    239 	    if (*pattern == '^' && pattern[1])
    240 		pattern += 2;
    241 	    else if (*pattern == '\\' && pattern[1])
    242 		pattern += 2;
    243 	    else
    244 		pattern++;
    245 	}
    246     }
    247 getout:
    248     return __UNCONST(pattern);			/* where we left off */
    249 }
    250 #endif
    251 
    252 static char *mygets(char *str, size_t n)
    253 {
    254     char *ret;
    255     size_t last;
    256 
    257     if ((ret = fgets(str, n, stdin)) != NULL) {
    258         last = strlen(str) - 1;
    259 
    260         if (str[last] == '\n')
    261             str[last] = '\0';
    262     }
    263 
    264     return ret;
    265 }
    266 
    267 /* interpret interpolations */
    268 
    269 char *
    270 dointerp(char *dest, size_t destsize, const char *pattern, const char *stoppers)
    271 {
    272     char *s;
    273     int i;
    274     char scrbuf[512];
    275     bool upper = false;
    276     bool lastcomp = false;
    277     int metabit = 0;
    278 
    279     while (*pattern && (!stoppers || !strchr(stoppers,*pattern))) {
    280 #ifdef DEBUGGING
    281 	if (debug & 8)
    282 	    printf("dointerp till %s at %s\r\n",stoppers?stoppers:"",pattern);
    283 #endif
    284 	if (*pattern == '%' && pattern[1]) {
    285 	    upper = false;
    286 	    lastcomp = false;
    287 	    for (s=NULL; !s; ) {
    288 		switch (*++pattern) {
    289 		case '^':
    290 		    upper = true;
    291 		    break;
    292 		case '_':
    293 		    lastcomp = true;
    294 		    break;
    295 		case '{':
    296 		    pattern = cpytill(scrbuf,pattern+1,'}');
    297 		    if ((s = strchr(scrbuf,'-')) != NULL)
    298 			*s++ = '\0';
    299 		    else
    300 			s = nullstr;
    301 		    s = getval(scrbuf,s);
    302 		    break;
    303 #ifdef CONDSUB
    304 		case '(': {
    305 		    char rch;
    306 		    bool matched;
    307 
    308 		    pattern = dointerp(dest,destsize,pattern+1,"!=");
    309 		    rch = *pattern;
    310 		    if (rch == '!')
    311 			pattern++;
    312 		    if (*pattern != '=')
    313 			goto getout;
    314 		    pattern = cpytill(scrbuf,pattern+1,'?');
    315 		    if (!*pattern)
    316 			goto getout;
    317 		    if (*scrbuf == '^' && scrbuf[strlen(scrbuf)-1] == '$') {
    318 			scrbuf[strlen(scrbuf)-1] = '\0';
    319 			matched = strEQ(scrbuf+1,dest);
    320 		    }
    321 		    else
    322 			matched = instr(dest,scrbuf) != NULL;
    323 		    if (matched==(rch == '=')) {
    324 			pattern = dointerp(dest,destsize,pattern+1,":)");
    325 			if (*pattern == ':')
    326 			    pattern = skipinterp(pattern+1,")");
    327 		    }
    328 		    else {
    329 			pattern = skipinterp(pattern+1,":)");
    330 			if (*pattern == ':')
    331 			    pattern++;
    332 			pattern = dointerp(dest,destsize,pattern,")");
    333 		    }
    334 		    s = dest;
    335 		    break;
    336 		}
    337 #endif
    338 #ifdef BACKTICK
    339 		case '`': {
    340 		    FILE *pipefp;
    341 
    342 		    pattern = dointerp(scrbuf,(sizeof scrbuf),pattern+1,"`");
    343 		    pipefp = popen(scrbuf,"r");
    344 		    if (pipefp != NULL) {
    345 			int len;
    346 
    347 			len = fread(scrbuf,sizeof(char),(sizeof scrbuf)-1,
    348 			    pipefp);
    349 			scrbuf[len] = '\0';
    350 			pclose(pipefp);
    351 		    }
    352 		    else {
    353 			printf("\r\nCan't run %s\r\n",scrbuf);
    354 			*scrbuf = '\0';
    355 		    }
    356 		    for (s=scrbuf; *s; s++) {
    357 			if (*s == '\n') {
    358 			    if (s[1])
    359 				*s = ' ';
    360 			    else
    361 				*s = '\0';
    362 			}
    363 		    }
    364 		    s = scrbuf;
    365 		    break;
    366 		}
    367 #endif
    368 #ifdef PROMPTTTY
    369 		case '"':
    370 		    pattern = dointerp(scrbuf,(sizeof scrbuf),pattern+1,"\"");
    371 		    fputs(scrbuf,stdout);
    372 		    resetty();
    373 		    mygets(scrbuf, sizeof(scrbuf));
    374 		    crmode();
    375 		    raw();
    376 		    noecho();
    377 		    nonl();
    378 		    s = scrbuf;
    379 		    break;
    380 #endif
    381 		case '~':
    382 		    s = homedir;
    383 		    break;
    384 		case '.':
    385 		    s = dotdir;
    386 		    break;
    387 		case '$':
    388 		    s = scrbuf;
    389 		    snprintf(scrbuf, sizeof(scrbuf), "%d",getpid());
    390 		    break;
    391 		case 'H':			/* host name */
    392 		    s = hostname;
    393 		    break;
    394 		case 'L':			/* login id */
    395 		    s = logname;
    396 		    break;
    397 		case 'N':			/* full name */
    398 		    s = getval("NAME",realname);
    399 		    break;
    400 		case 'O':
    401 		    s = origdir;
    402 		    break;
    403 		case 'p':
    404 		    s = cwd;
    405 		    break;
    406 		case 'X':			/* warp library */
    407 		    s = warplib;
    408 		    break;
    409 		default:
    410 		    if (--destsize <= 0)
    411 			abort_interp();
    412 		    *dest++ = *pattern | metabit;
    413 		    s = nullstr;
    414 		    break;
    415 		}
    416 	    }
    417 	    if (!s)
    418 		s = nullstr;
    419 	    pattern++;
    420 	    if (upper || lastcomp) {
    421 		char *t;
    422 
    423 		if (s != scrbuf) {
    424 		    safecpy(scrbuf,s,(sizeof scrbuf));
    425 		    s = scrbuf;
    426 		}
    427 		if (upper || !(t=strrchr(s,'/')))
    428 		    t = s;
    429 		while (*t && !isalpha((unsigned char)*t)) {
    430 		    t++;
    431 		    *t = toupper((unsigned char)*t);
    432 		}
    433 	    }
    434 	    i = metabit;		/* maybe get into register */
    435 	    if (s == dest) {
    436 		while (*dest) {
    437 		    if (--destsize <= 0)
    438 			abort_interp();
    439 		    *dest++ |= i;
    440 		}
    441 	    }
    442 	    else {
    443 		while (*s) {
    444 		    if (--destsize <= 0)
    445 			abort_interp();
    446 		    *dest++ = *s++ | i;
    447 		}
    448 	    }
    449 	}
    450 	else {
    451 	    if (--destsize <= 0)
    452 		abort_interp();
    453 	    if (*pattern == '^' && pattern[1]) {
    454 		++pattern;			/* skip uparrow */
    455 		i = *pattern;		/* get char into a register */
    456 		if (i == '?')
    457 		    *dest++ = '\177' | metabit;
    458 		else if (i == '(') {
    459 		    metabit = 0200;
    460 		    destsize++;
    461 		}
    462 		else if (i == ')') {
    463 		    metabit = 0;
    464 		    destsize++;
    465 		}
    466 		else
    467 		    *dest++ = (i & 037) | metabit;
    468 		pattern++;
    469 	    }
    470 	    else if (*pattern == '\\' && pattern[1]) {
    471 		++pattern;			/* skip backslash */
    472 		i = *pattern;		/* get char into a register */
    473 
    474 		/* this used to be a switch but the if may save space */
    475 
    476 		if (i >= '0' && i <= '7') {
    477 		    i = 1;
    478 		    while (i < 01000 && *pattern >= '0' && *pattern <= '7') {
    479 			i <<= 3;
    480 			i += *pattern++ - '0';
    481 		    }
    482 		    *dest++ = (i & 0377) | metabit;
    483 		    --pattern;
    484 		}
    485 		else if (i == 'b')
    486 		    *dest++ = '\b' | metabit;
    487 		else if (i == 'f')
    488 		    *dest++ = '\f' | metabit;
    489 		else if (i == 'n')
    490 		    *dest++ = '\n' | metabit;
    491 		else if (i == 'r')
    492 		    *dest++ = '\r' | metabit;
    493 		else if (i == 't')
    494 		    *dest++ = '\t' | metabit;
    495 		else
    496 		    *dest++ = i | metabit;
    497 		pattern++;
    498 	    }
    499 	    else
    500 		*dest++ = *pattern++ | metabit;
    501 	}
    502     }
    503     *dest = '\0';
    504 getout:
    505     return __UNCONST(pattern);			/* where we left off */
    506 }
    507 
    508 void
    509 interp(char *dest, size_t destsize, const char *pattern)
    510 {
    511     (void) dointerp(dest,destsize,pattern,NULL);
    512 #ifdef DEBUGGING
    513     if (debug & DEB_FILEXP)
    514 	fputs(dest,stdout);
    515 #endif
    516 }
    517 
    518 /* get the person's real name from /etc/passwd */
    519 /* (string is overwritten, so it must be copied) */
    520 
    521 static char *
    522 getrealname(uid_t uid)
    523 {
    524     char *s, *c;
    525 
    526 #ifdef PASSNAMES
    527     struct passwd *pwd = getpwuid(uid);
    528 
    529     s = pwd->pw_gecos;
    530 #ifdef BERKNAMES
    531 #ifdef BERKJUNK
    532     while (*s && !isalnum(*s) && *s != '&') s++;
    533 #endif
    534     if ((c = strchr(s, ',')) != NULL)
    535 	*c = '\0';
    536     if ((c = strchr(s, ';')) != NULL)
    537 	*c = '\0';
    538     s = cpytill(buf,s,'&');
    539     if (*s == '&') {			/* whoever thought this one up was */
    540 	c = buf + strlen(buf);		/* in the middle of the night */
    541 	strcat(c,logname);		/* before the morning after */
    542 	strcat(c,s+1);
    543 	if (islower((unsigned char)*c))
    544 	    *c = toupper((unsigned char)*c);		/* gack and double gack */
    545     }
    546 #else
    547     if ((c = strchr(s, '(')) != NULL)
    548 	*c = '\0';
    549     if ((c = strchr(s, '-')) != NULL)
    550 	s = c;
    551     strcpy(buf,tmpbuf);
    552 #endif
    553     endpwent();
    554     return buf;				/* return something static */
    555 #else
    556     if ((tmpfp=fopen(filexp(FULLNAMEFILE),"r")) != NULL) {
    557 	fgets(buf,sizeof buf,tmpfp);
    558 	fclose(tmpfp);
    559     }
    560     else {
    561 	resetty();
    562 	printf("What is your name? ");
    563 	fgets(buf,(sizeof buf),stdin);
    564 	crmode();
    565 	raw();
    566 	noecho();
    567 	nonl();
    568 	if (fork())
    569 	    wait(0);
    570 	else {
    571 	    setgid(getgid());
    572 	    if ((tmpfp = fopen(filexp(FULLNAMEFILE),"w")) == NULL)
    573 		exit(1);
    574 	    fprintf(tmpfp, "%s\n", buf);
    575 	    fclose(tmpfp);
    576 	    exit(0);
    577 	}
    578     }
    579     buf[strlen(buf)-1] = '\0';
    580     return buf;
    581 #endif
    582 }
    583 
    584 static void
    585 abort_interp(void)
    586 {
    587     fputs("\r\n% interp buffer overflow!\r\n",stdout);
    588     sig_catcher(0);
    589 }
    590