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