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