xref: /netbsd-src/games/warp/intrp.c (revision 1182a44c59cae4d586117d55eca24b4b8b173211)
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
intrp_init(char * tcbuf)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 *
filexp(const char * s)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 *
skipinterp(const char * pattern,const char * stoppers)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 
mygets(char * str,size_t n)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 *
dointerp(char * dest,size_t destsize,const char * pattern,const char * stoppers)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
interp(char * dest,size_t destsize,const char * pattern)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 *
getrealname(uid_t uid)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
abort_interp(void)585 abort_interp(void)
586 {
587     fputs("\r\n% interp buffer overflow!\r\n",stdout);
588     sig_catcher(0);
589 }
590