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 26static char *tildename = NULL; 27static char *tildedir = NULL; 28#endif 29 30static char *getrealname(uid_t); 31#ifdef CONDSUB 32static char *skipinterp(const char *, const char *); 33#endif 34 35__dead static void abort_interp(void); 36 37void 38intrp_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 91char * 92filexp(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 190static char * 191skipinterp(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 } 247getout: 248 return __UNCONST(pattern); /* where we left off */ 249} 250#endif 251 252static 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 269char * 270dointerp(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'; 504getout: 505 return __UNCONST(pattern); /* where we left off */ 506} 507 508void 509interp(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 521static char * 522getrealname(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 584static void 585abort_interp(void) 586{ 587 fputs("\r\n% interp buffer overflow!\r\n",stdout); 588 sig_catcher(0); 589} 590