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