1: /* $Header: /home/hyperion/mu/christos/src/sys/tcsh-6.00/RCS/tc.func.c,v 3.0 1991/07/04 21:49:28 christos Exp $ */ 2: /* 3: * tc.func.c: New tcsh builtins. 4: */ 5: /*- 6: * Copyright (c) 1980, 1991 The Regents of the University of California. 7: * All rights reserved. 8: * 9: * Redistribution and use in source and binary forms, with or without 10: * modification, are permitted provided that the following conditions 11: * are met: 12: * 1. Redistributions of source code must retain the above copyright 13: * notice, this list of conditions and the following disclaimer. 14: * 2. Redistributions in binary form must reproduce the above copyright 15: * notice, this list of conditions and the following disclaimer in the 16: * documentation and/or other materials provided with the distribution. 17: * 3. All advertising materials mentioning features or use of this software 18: * must display the following acknowledgement: 19: * This product includes software developed by the University of 20: * California, Berkeley and its contributors. 21: * 4. Neither the name of the University nor the names of its contributors 22: * may be used to endorse or promote products derived from this software 23: * without specific prior written permission. 24: * 25: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 26: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 29: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 30: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 31: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 32: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 33: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 34: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 35: * SUCH DAMAGE. 36: */ 37: #include "config.h" 38: #if !defined(lint) && !defined(pdp11) 39: static char *rcsid() 40: { return "$Id: tc.func.c,v 3.0 1991/07/04 21:49:28 christos Exp $"; } 41: #endif 42: 43: #include "sh.h" 44: #include "ed.h" 45: #include "ed.defns.h" /* for the function names */ 46: #include "tw.h" 47: 48: extern time_t t_period; 49: static bool precmd_active = 0; 50: static bool periodic_active = 0; 51: static bool cwdcmd_active = 0; /* PWP: for cwd_cmd */ 52: 53: static void Reverse __P((Char *)); 54: static void auto_logout __P((void)); 55: static void insert __P((struct wordent *, bool)); 56: static void insert_we __P((struct wordent *, struct wordent *)); 57: static int inlist __P((Char *, Char *)); 58: 59: 60: /* 61: * Tops-C shell 62: */ 63: 64: /* 65: * expand_lex: Take the given lex and put an expanded version of it in the 66: * string buf. First guy in lex list is ignored; last guy is ^J which we 67: * ignore Only take lex'es from position from to position to inclusive Note: 68: * csh sometimes sets bit 8 in characters which causes all kinds of problems 69: * if we don't mask it here. Note: excl's in lexes have been un-back-slashed 70: * and must be re-back-slashed 71: * (PWP: NOTE: this returns a pointer to the END of the string expanded 72: * (in other words, where the NUL is).) 73: */ 74: /* PWP: this is a combination of the old sprlex() and the expand_lex from 75: the magic-space stuff */ 76: 77: Char * 78: expand_lex(buf, bufsiz, sp0, from, to) 79: Char *buf; 80: int bufsiz; 81: struct wordent *sp0; 82: int from, to; 83: { 84: register struct wordent *sp; 85: register Char *s, *d, *e; 86: register Char prev_c; 87: register int i; 88: 89: buf[0] = '\0'; 90: prev_c = '\0'; 91: d = buf; 92: e = &buf[bufsiz]; /* for bounds checking */ 93: 94: if (!sp0) 95: return (buf); /* null lex */ 96: if ((sp = sp0->next) == sp0) 97: return (buf); /* nada */ 98: if (sp == (sp0 = sp0->prev)) 99: return (buf); /* nada */ 100: 101: for (i = 0; i < NCARGS; i++) { 102: if ((i >= from) && (i <= to)) { /* if in range */ 103: for (s = sp->word; *s && d < e; s++) { 104: /* 105: * bugfix by Michael Bloom: anything but the current history 106: * character {(PWP) and backslash} seem to be dealt with 107: * elsewhere. 108: */ 109: if ((*s & QUOTE) 110: && (((*s & TRIM) == HIST) || 111: ((*s & TRIM) == '\\') && (prev_c != '\\'))) { 112: *d++ = '\\'; 113: } 114: *d++ = (*s & TRIM); 115: prev_c = *s; 116: } 117: if (d < e) 118: *d++ = ' '; 119: } 120: sp = sp->next; 121: if (sp == sp0) 122: break; 123: } 124: if (d > buf) 125: d--; /* get rid of trailing space */ 126: 127: return (d); 128: } 129: 130: Char * 131: sprlex(buf, sp0) 132: Char *buf; 133: struct wordent *sp0; 134: { 135: Char *cp; 136: 137: cp = expand_lex(buf, INBUFSIZ, sp0, 0, NCARGS); 138: *cp = '\0'; 139: return (buf); 140: } 141: 142: void 143: Itoa(n, s) /* convert n to characters in s */ 144: int n; 145: Char *s; 146: { 147: int i, sign; 148: 149: if ((sign = n) < 0) /* record sign */ 150: n = -n; 151: i = 0; 152: do { 153: s[i++] = n % 10 + '0'; 154: } while ((n /= 10) > 0); 155: if (sign < 0) 156: s[i++] = '-'; 157: s[i] = '\0'; 158: Reverse(s); 159: } 160: 161: static void 162: Reverse(s) 163: Char *s; 164: { 165: int c, i, j; 166: 167: for (i = 0, j = Strlen(s) - 1; i < j; i++, j--) { 168: c = s[i]; 169: s[i] = s[j]; 170: s[j] = c; 171: } 172: } 173: 174: 175: void 176: dolist(v) 177: register Char **v; 178: { 179: int i, k; 180: struct stat st; 181: 182: if (*++v == NULL) { 183: (void) t_search(STRNULL, NULL, LIST, 0, 0, 0); 184: return; 185: } 186: gflag = 0; 187: tglob(v); 188: if (gflag) { 189: v = globall(v); 190: if (v == 0) 191: stderror(ERR_NAME | ERR_NOMATCH); 192: } 193: else 194: v = gargv = saveblk(v); 195: trim(v); 196: for (k = 0; v[k] != NULL && v[k][0] != '-'; k++); 197: if (v[k]) { 198: /* 199: * We cannot process a flag therefore we let ls do it right. 200: */ 201: static Char STRls[] = 202: {'l', 's', '\0'}; 203: static Char STRmCF[] = 204: {'-', 'C', 'F', '\0'}; 205: struct command *t; 206: struct wordent cmd, *nextword, *lastword; 207: Char *cp; 208: 209: #ifdef BSDSIGS 210: sigmask_t omask = 0; 211: 212: if (setintr) 213: omask = sigblock(sigmask(SIGINT)) & ~sigmask(SIGINT); 214: #else 215: sighold(SIGINT); 216: #endif 217: if (seterr) { 218: xfree((ptr_t) seterr); 219: seterr = NULL; 220: } 221: cmd.word = STRNULL; 222: lastword = &cmd; 223: nextword = (struct wordent *) xcalloc(1, sizeof cmd); 224: nextword->word = Strsave(STRls); 225: lastword->next = nextword; 226: nextword->prev = lastword; 227: lastword = nextword; 228: nextword = (struct wordent *) xcalloc(1, sizeof cmd); 229: nextword->word = Strsave(STRmCF); 230: lastword->next = nextword; 231: nextword->prev = lastword; 232: lastword = nextword; 233: for (cp = *v; cp; cp = *++v) { 234: nextword = (struct wordent *) xcalloc(1, sizeof cmd); 235: nextword->word = Strsave(cp); 236: lastword->next = nextword; 237: nextword->prev = lastword; 238: lastword = nextword; 239: } 240: lastword->next = &cmd; 241: cmd.prev = lastword; 242: 243: /* build a syntax tree for the command. */ 244: t = syntax(cmd.next, &cmd, 0); 245: if (seterr) 246: stderror(ERR_OLD); 247: /* expand aliases like process() does */ 248: /* alias(&cmd); */ 249: /* execute the parse tree. */ 250: execute(t, tpgrp > 0 ? tpgrp : -1, NULL, NULL); 251: /* done. free the lex list and parse tree. */ 252: freelex(&cmd), freesyn(t); 253: if (setintr) 254: #ifdef BSDSIGS 255: (void) sigsetmask(omask); 256: #else 257: (void) sigrelse(SIGINT); 258: #endif 259: } 260: else { 261: Char *dp, *tmp, buf[MAXPATHLEN]; 262: 263: for (k = 0, i = 0; v[k] != NULL; k++) { 264: tmp = dnormalize(v[k]); 265: dp = &tmp[Strlen(tmp) - 1]; 266: if (*dp == '/' && dp != tmp) 267: #ifdef apollo 268: if (dp != &tmp[1]) 269: #endif 270: *dp = '\0'; 271: if (stat(short2str(tmp), &st) == -1) { 272: if (k != i) { 273: if (i != 0) 274: xputchar('\n'); 275: print_by_column(STRNULL, &v[i], k - i, FALSE); 276: } 277: xprintf("%s: %s.\n", short2str(tmp), strerror(errno)); 278: i = k + 1; 279: } 280: else if (S_ISDIR(st.st_mode)) { 281: Char *cp; 282: 283: if (k != i) { 284: if (i != 0) 285: xputchar('\n'); 286: print_by_column(STRNULL, &v[i], k - i, FALSE); 287: } 288: if (k != 0 && v[1] != NULL) 289: xputchar('\n'); 290: xprintf("%s:\n", short2str(tmp)); 291: for (cp = tmp, dp = buf; *cp; *dp++ = (*cp++ | QUOTE)); 292: if (dp[-1] != (Char) ('/' | QUOTE)) 293: *dp++ = '/'; 294: else 295: dp[-1] &= TRIM; 296: *dp = '\0'; 297: (void) t_search(buf, NULL, LIST, 0, 0, 0); 298: i = k + 1; 299: } 300: xfree((ptr_t) tmp); 301: } 302: if (k != i) { 303: if (i != 0) 304: xputchar('\n'); 305: print_by_column(STRNULL, &v[i], k - i, FALSE); 306: } 307: } 308: 309: if (gargv) { 310: blkfree(gargv); 311: gargv = 0; 312: } 313: } 314: 315: static char *d_tell = "ALL"; 316: extern bool GotTermCaps; 317: 318: void 319: dotelltc(v) 320: register Char **v; 321: { 322: 323: if (!GotTermCaps) 324: GetTermCaps(); 325: 326: TellTC(v[1] ? short2str(v[1]) : d_tell); 327: } 328: 329: void 330: doechotc(v) 331: register Char **v; 332: { 333: if (!GotTermCaps) 334: GetTermCaps(); 335: EchoTC(++v); 336: } 337: 338: void 339: dosettc(v) 340: Char **v; 341: { 342: char tv[2][BUFSIZ]; 343: 344: if (!GotTermCaps) 345: GetTermCaps(); 346: 347: (void) strcpy(tv[0], short2str(v[1])); 348: (void) strcpy(tv[1], short2str(v[2])); 349: SetTC(tv[0], tv[1]); 350: } 351: 352: /* The dowhich() is by: 353: * Andreas Luik <luik@isaak.isa.de> 354: * I S A GmbH - Informationssysteme fuer computerintegrierte Automatisierung 355: * Azenberstr. 35 356: * D-7000 Stuttgart 1 357: * West-Germany 358: * Thanks!! 359: */ 360: 361: void 362: dowhich(v) 363: register Char **v; 364: { 365: struct wordent lex[3]; 366: struct varent *vp; 367: 368: lex[0].next = &lex[1]; 369: lex[1].next = &lex[2]; 370: lex[2].next = &lex[0]; 371: 372: lex[0].prev = &lex[2]; 373: lex[1].prev = &lex[0]; 374: lex[2].prev = &lex[1]; 375: 376: lex[0].word = STRNULL; 377: lex[2].word = STRret; 378: 379: while (*++v) { 380: if (vp = adrof1(*v, &aliases)) { 381: xprintf("%s: \t aliased to ", short2str(*v)); 382: blkpr(vp->vec); 383: xprintf("\n"); 384: } 385: else { 386: lex[1].word = *v; 387: tellmewhat(lex); 388: } 389: } 390: } 391: 392: /* PWP: a hack to start up your stopped editor on a single keystroke */ 393: /* jbs - fixed hack so it worked :-) 3/28/89 */ 394: 395: struct process * 396: find_stop_ed() 397: { 398: register struct process *pp; 399: register char *ep, *vp, *p; 400: int epl, vpl; 401: 402: if ((ep = getenv("EDITOR")) != NULL) { /* if we have a value */ 403: if ((p = strrchr(ep, '/')) != NULL) { /* if it has a path */ 404: ep = p + 1; /* then we want only the last part */ 405: } 406: } 407: else { 408: ep = "ed"; 409: } 410: if ((vp = getenv("VISUAL")) != NULL) { /* if we have a value */ 411: if ((p = strrchr(vp, '/')) != NULL) { /* and it has a path */ 412: vp = p + 1; /* then we want only the last part */ 413: } 414: } 415: else { 416: vp = "vi"; 417: } 418: vpl = strlen(vp); 419: epl = strlen(ep); 420: 421: if (pcurrent == PNULL) /* see if we have any jobs */ 422: return PNULL; /* nope */ 423: 424: for (pp = proclist.p_next; pp; pp = pp->p_next) { 425: if (pp->p_pid == pp->p_jobid) { 426: p = short2str(pp->p_command); 427: /* if we find either in the current name, fg it */ 428: if (strncmp(ep, p, (size_t) epl) == 0 || 429: strncmp(vp, p, (size_t) vpl) == 0) 430: return pp; 431: } 432: } 433: return PNULL; /* didn't find a job */ 434: } 435: 436: void 437: fg_proc_entry(pp) 438: register struct process *pp; 439: { 440: #ifdef BSDSIGS 441: sigmask_t omask; 442: #endif 443: jmp_buf osetexit; 444: bool ohaderr; 445: 446: getexit(osetexit); 447: 448: #ifdef BSDSIGS 449: omask = sigblock(sigmask(SIGINT)); 450: #else 451: (void) sighold(SIGINT); 452: #endif 453: 454: ohaderr = haderr; /* we need to ignore setting of haderr due to 455: * process getting stopped by a signal */ 456: if (setexit() == 0) { /* come back here after pjwait */ 457: pendjob(); 458: pstart(pp, 1); /* found it. */ 459: pjwait(pp); 460: } 461: 462: resexit(osetexit); 463: haderr = ohaderr; 464: 465: #ifdef BSDSIGS 466: (void) sigsetmask(omask); 467: #else 468: (void) sigrelse(SIGINT); 469: #endif 470: 471: } 472: 473: static void 474: auto_logout() 475: { 476: xprintf("auto-logout\n"); 477: /* Don't leave the tty in raw mode */ 478: if (editing) 479: (void) Cookedmode(); 480: (void) close(SHIN); 481: set(STRlogout, Strsave(STRa_matic)); 482: child = 1; 483: #ifdef TESLA 484: do_logout = 1; 485: #endif /* TESLA */ 486: goodbye(); 487: } 488: 489: sigret_t 490: /*ARGSUSED*/ 491: alrmcatch(snum) 492: int snum; 493: { 494: time_t cl, nl; 495: 496: if ((nl = sched_next()) == -1) 497: auto_logout(); /* no other possibility - logout */ 498: (void) time(&cl); 499: if (nl <= cl + 1) 500: sched_run(); 501: else 502: auto_logout(); 503: setalarm(); 504: #ifndef SIGVOID 505: return (snum); 506: #endif 507: } 508: 509: /* 510: * Karl Kleinpaste, 21oct1983. 511: * Added precmd(), which checks for the alias 512: * precmd in aliases. If it's there, the alias 513: * is executed as a command. This is done 514: * after mailchk() and just before print- 515: * ing the prompt. Useful for things like printing 516: * one's current directory just before each command. 517: */ 518: void 519: precmd() 520: { 521: #ifdef BSDSIGS 522: sigmask_t omask; 523: #endif 524: 525: #ifdef BSDSIGS 526: omask = sigblock(sigmask(SIGINT)); 527: #else 528: (void) sighold(SIGINT); 529: #endif 530: if (precmd_active) { /* an error must have been caught */ 531: aliasrun(2, STRunalias, STRprecmd); 532: xprintf("Faulty alias 'precmd' removed.\n"); 533: goto leave; 534: } 535: precmd_active = 1; 536: if (!whyles && adrof1(STRprecmd, &aliases)) 537: aliasrun(1, STRprecmd, NULL); 538: leave: 539: precmd_active = 0; 540: #ifdef BSDSIGS 541: (void) sigsetmask(omask); 542: #else 543: (void) sigrelse(SIGINT); 544: #endif 545: } 546: 547: /* 548: * Paul Placeway 11/24/87 Added cwd_cmd by hacking precmd() into 549: * submission... Run every time $cwd is set (after it is set). Useful 550: * for putting your machine and cwd (or anything else) in an xterm title 551: * space. 552: */ 553: void 554: cwd_cmd() 555: { 556: #ifdef BSDSIGS 557: sigmask_t omask; 558: #endif 559: 560: #ifdef BSDSIGS 561: omask = sigblock(sigmask(SIGINT)); 562: #else 563: (void) sighold(SIGINT); 564: #endif 565: if (cwdcmd_active) { /* an error must have been caught */ 566: aliasrun(2, STRunalias, STRcwdcmd); 567: xprintf("Faulty alias 'cwdcmd' removed.\n"); 568: goto leave; 569: } 570: cwdcmd_active = 1; 571: if (!whyles && adrof1(STRcwdcmd, &aliases)) 572: aliasrun(1, STRcwdcmd, NULL); 573: leave: 574: cwdcmd_active = 0; 575: #ifdef BSDSIGS 576: (void) sigsetmask(omask); 577: #else 578: (void) sigrelse(SIGINT); 579: #endif 580: } 581: 582: 583: /* 584: * Karl Kleinpaste, 18 Jan 1984. 585: * Added period_cmd(), which executes the alias "periodic" every 586: * $tperiod minutes. Useful for occasional checking of msgs and such. 587: */ 588: void 589: period_cmd() 590: { 591: register Char *vp; 592: time_t t, interval; 593: #ifdef BSDSIGS 594: sigmask_t omask; 595: #endif 596: 597: #ifdef BSDSIGS 598: omask = sigblock(sigmask(SIGINT)); 599: #else 600: (void) sighold(SIGINT); 601: #endif 602: if (periodic_active) { /* an error must have been caught */ 603: aliasrun(2, STRunalias, STRperiodic); 604: xprintf("Faulty alias 'periodic' removed.\n"); 605: goto leave; 606: } 607: periodic_active = 1; 608: if (!whyles && adrof1(STRperiodic, &aliases)) { 609: vp = value(STRtperiod); 610: if (vp == NOSTR) 611: return; 612: interval = getn(vp); 613: (void) time(&t); 614: if (t - t_period >= interval * 60) { 615: t_period = t; 616: aliasrun(1, STRperiodic, NULL); 617: } 618: } 619: leave: 620: periodic_active = 0; 621: #ifdef BSDSIGS 622: (void) sigsetmask(omask); 623: #else 624: (void) sigrelse(SIGINT); 625: #endif 626: } 627: 628: /* 629: * Karl Kleinpaste, 21oct1983. 630: * Set up a one-word alias command, for use for special things. 631: * This code is based on the mainline of process(). 632: */ 633: void 634: aliasrun(cnt, s1, s2) 635: int cnt; 636: Char *s1, *s2; 637: { 638: struct wordent w, *new1, *new2; /* for holding alias name */ 639: struct command *t = NULL; 640: jmp_buf osetexit; 641: 642: getexit(osetexit); 643: if (seterr) { 644: xfree((ptr_t) seterr); 645: seterr = NULL; /* don't repeatedly print err msg. */ 646: } 647: w.word = STRNULL; 648: new1 = (struct wordent *) xcalloc(1, sizeof w); 649: new1->word = Strsave(s1); 650: if (cnt == 1) { 651: /* build a lex list with one word. */ 652: w.next = w.prev = new1; 653: new1->next = new1->prev = &w; 654: } 655: else { 656: /* build a lex list with two words. */ 657: new2 = (struct wordent *) xcalloc(1, sizeof w); 658: new2->word = Strsave(s2); 659: w.next = new2->prev = new1; 660: new1->next = w.prev = new2; 661: new1->prev = new2->next = &w; 662: } 663: 664: /* expand aliases like process() does. */ 665: alias(&w); 666: /* build a syntax tree for the command. */ 667: t = syntax(w.next, &w, 0); 668: if (seterr) 669: stderror(ERR_OLD); 670: 671: psavejob(); 672: /* catch any errors here */ 673: if (setexit() == 0) 674: /* execute the parse tree. */ 675: /* 676: * From: Michael Schroeder <mlschroe@immd4.informatik.uni-erlangen.de> 677: * was execute(t, tpgrp); 678: */ 679: execute(t, tpgrp > 0 ? tpgrp : -1, NULL, NULL); 680: /* done. free the lex list and parse tree. */ 681: freelex(&w), freesyn(t); 682: if (haderr) { 683: haderr = 0; 684: /* 685: * Either precmd, or cwdcmd, or periodic had an error. Call it again so 686: * that it is removed 687: */ 688: if (precmd_active) 689: precmd(); 690: #ifdef notdef 691: /* 692: * XXX: On the other hand, just interrupting them causes an error too. 693: * So if we hit ^C in the middle of cwdcmd or periodic the alias gets 694: * removed. We don't want that. Note that we want to remove precmd 695: * though, cause that could lead into an infinite loop. This should be 696: * fixed correctly, but then haderr should give us the whole exit 697: * status not just true or false. 698: */ 699: else if (cwdcmd_active) 700: cwd_cmd(); 701: else if (periodic_active) 702: period_cmd(); 703: #endif 704: } 705: /* reset the error catcher to the old place */ 706: resexit(osetexit); 707: prestjob(); 708: pendjob(); 709: } 710: 711: void 712: setalarm() 713: { 714: struct varent *vp; 715: Char *cp; 716: unsigned alrm_time = 0; 717: long cl, nl, sched_dif; 718: 719: if (vp = adrof(STRa_logout)) { 720: if (cp = vp->vec[0]) 721: alrm_time = (atoi(short2str(cp)) * 60); 722: } 723: if ((nl = sched_next()) != -1) { 724: (void) time(&cl); 725: sched_dif = nl - cl; 726: if ((alrm_time == 0) || (sched_dif < alrm_time)) 727: alrm_time = ((int) sched_dif) + 1; 728: } 729: (void) alarm(alrm_time); /* Autologout ON */ 730: } 731: 732: #define RMDEBUG /* For now... */ 733: 734: void 735: rmstar(cp) 736: struct wordent *cp; 737: { 738: struct wordent *we, *args; 739: register struct wordent *tmp, *del; 740: 741: #ifdef RMDEBUG 742: static Char STRrmdebug[] = 743: {'r', 'm', 'd', 'e', 'b', 'u', 'g', '\0'}; 744: Char *tag; 745: 746: #endif 747: Char *charac; 748: char c; 749: int ask, doit, star = 0, silent = 0; 750: 751: if (!adrof(STRrmstar)) 752: return; 753: #ifdef RMDEBUG 754: tag = value(STRrmdebug); 755: #endif 756: we = cp->next; 757: while (*we->word == ';' && we != cp) 758: we = we->next; 759: while (we != cp) { 760: #ifdef RMDEBUG 761: if (*tag) 762: xprintf("parsing command line\n"); 763: #endif 764: if (!Strcmp(we->word, STRrm)) { 765: args = we->next; 766: ask = (*args->word != '-'); 767: while (*args->word == '-' && !silent) { /* check options */ 768: for (charac = (args->word + 1); *charac && !silent; charac++) 769: silent = (*charac == 'i' || *charac == 'f'); 770: args = args->next; 771: } 772: ask = (ask || !ask && !silent); 773: if (ask) { 774: for (; !star && *args->word != ';' 775: && args != cp; args = args->next) 776: if (!Strcmp(args->word, STRstar)) 777: star = 1; 778: if (ask && star) { 779: xprintf("Do you really want to delete all files? [n/y] "); 780: flush(); 781: (void) read(SHIN, &c, 1); 782: doit = (c == 'Y' || c == 'y'); 783: while (c != '\n') 784: (void) read(SHIN, &c, 1); 785: if (!doit) { 786: /* remove the command instead */ 787: if (*tag) 788: xprintf("skipping deletion of files!\n"); 789: for (tmp = we; 790: *tmp->word != '\n' && 791: *tmp->word != ';' && tmp != cp;) { 792: tmp->prev->next = tmp->next; 793: tmp->next->prev = tmp->prev; 794: xfree((ptr_t) tmp->word); 795: del = tmp; 796: tmp = tmp->next; 797: xfree((ptr_t) del); 798: } 799: if (*tmp->word == ';') { 800: tmp->prev->next = tmp->next; 801: tmp->next->prev = tmp->prev; 802: xfree((ptr_t) tmp->word); 803: del = tmp; 804: xfree((ptr_t) del); 805: } 806: } 807: } 808: } 809: } 810: for (we = we->next; 811: *we->word != ';' && we != cp; 812: we = we->next); 813: if (*we->word == ';') 814: we = we->next; 815: } 816: #ifdef RMDEBUG 817: if (*tag) { 818: xprintf("command line now is:\n"); 819: for (we = cp->next; we != cp; we = we->next) 820: xprintf("%s ", short2str(we->word)); 821: } 822: #endif 823: return; 824: } 825: 826: #ifdef BSDJOBS 827: /* Check if command is in continue list 828: and do a "aliasing" if it exists as a job in background */ 829: 830: #define CNDEBUG /* For now */ 831: void 832: con_jobs(cp) 833: struct wordent *cp; 834: { 835: struct wordent *we; 836: register struct process *pp, *np; 837: Char *cmd, *con_list, *con_args_list; 838: 839: #ifdef CNDEBUG 840: Char *tag; 841: static Char STRcndebug[] = 842: {'c', 'n', 'd', 'e', 'b', 'u', 'g', '\0'}; 843: 844: #endif 845: bool in_c__list, in_c__arg_list; 846: 847: 848: #ifdef CNDEBUG 849: tag = value(STRcndebug); 850: #endif 851: con_list = value(STRcontinue); 852: con_args_list = value(STRcon_args); 853: if (*con_list == '\0' && *con_args_list == '\0') 854: return; 855: 856: we = cp->next; 857: while (*we->word == ';' && we != cp) 858: we = we->next; 859: while (we != cp) { 860: #ifdef CNDEBUG 861: if (*tag) 862: xprintf("parsing command line\n"); 863: #endif 864: cmd = we->word; 865: in_c__list = inlist(con_list, cmd); 866: in_c__arg_list = inlist(con_args_list, cmd); 867: if (in_c__list || in_c__arg_list) { 868: #ifdef CNDEBUG 869: if (*tag) 870: xprintf("in one of the lists\n"); 871: #endif 872: np = PNULL; 873: for (pp = proclist.p_next; pp; pp = pp->p_next) { 874: if (prefix(cmd, pp->p_command)) { 875: if (pp->p_index) { 876: np = pp; 877: break; 878: } 879: } 880: } 881: if (np) { 882: insert(we, in_c__arg_list); 883: } 884: } 885: for (we = we->next; 886: *we->word != ';' && we != cp; 887: we = we->next); 888: if (*we->word == ';') 889: we = we->next; 890: } 891: #ifdef CNDEBUG 892: if (*tag) { 893: xprintf("command line now is:\n"); 894: for (we = cp->next; we != cp; we = we->next) 895: xprintf("%s ", 896: short2str(we->word)); 897: } 898: #endif 899: return; 900: } 901: 902: /* The actual "aliasing" of for backgrounds() is done here 903: with the aid of insert_we(). */ 904: static void 905: insert(plist, file_args) 906: struct wordent *plist; 907: bool file_args; 908: { 909: struct wordent *now, *last; 910: Char *cmd, *bcmd, *cp1, *cp2; 911: int cmd_len; 912: Char *pause = STRunderpause; 913: int p_len = Strlen(pause); 914: 915: cmd_len = Strlen(plist->word); 916: cmd = (Char *) xcalloc(1, (size_t) ((cmd_len + 1) * sizeof(Char))); 917: (void) Strcpy(cmd, plist->word); 918: /* Do insertions at beginning, first replace command word */ 919: 920: if (file_args) { 921: now = plist; 922: xfree((ptr_t) now->word); 923: now->word = (Char *) xcalloc(1, (size_t) (5 * sizeof(Char))); 924: (void) Strcpy(now->word, STRecho); 925: 926: now = (struct wordent *) xcalloc(1, (size_t) sizeof(struct wordent)); 927: now->word = (Char *) xcalloc(1, (size_t) (6 * sizeof(Char))); 928: (void) Strcpy(now->word, STRbKqpwd); 929: insert_we(now, plist); 930: 931: for (last = now; *last->word != '\n' && *last->word != ';'; 932: last = last->next); 933: 934: now = (struct wordent *) xcalloc(1, (size_t) sizeof(struct wordent)); 935: now->word = (Char *) xcalloc(1, (size_t) (2 * sizeof(Char))); 936: (void) Strcpy(now->word, STRgt); 937: insert_we(now, last->prev); 938: 939: now = (struct wordent *) xcalloc(1, (size_t) sizeof(struct wordent)); 940: now->word = (Char *) xcalloc(1, (size_t) (2 * sizeof(Char))); 941: (void) Strcpy(now->word, STRbang); 942: insert_we(now, last->prev); 943: 944: now = (struct wordent *) xcalloc(1, (size_t) sizeof(struct wordent)); 945: now->word = (Char *) xcalloc(1, (size_t) cmd_len + p_len + 4); 946: cp1 = now->word; 947: cp2 = cmd; 948: *cp1++ = '~'; 949: *cp1++ = '/'; 950: *cp1++ = '.'; 951: while (*cp1++ = *cp2++); 952: cp1--; 953: cp2 = pause; 954: while (*cp1++ = *cp2++); 955: insert_we(now, last->prev); 956: 957: now = (struct wordent *) xcalloc(1, (size_t) sizeof(struct wordent)); 958: now->word = (Char *) xcalloc(1, (size_t) (2 * sizeof(Char))); 959: (void) Strcpy(now->word, STRsm); 960: insert_we(now, last->prev); 961: bcmd = (Char *) xcalloc(1, (size_t) ((cmd_len + 2) * sizeof(Char))); 962: cp1 = bcmd; 963: cp2 = cmd; 964: *cp1++ = '%'; 965: while (*cp1++ = *cp2++); 966: now = (struct wordent *) xcalloc(1, (size_t) (sizeof(struct wordent))); 967: now->word = bcmd; 968: insert_we(now, last->prev); 969: } 970: else { 971: struct wordent *del; 972: 973: now = plist; 974: xfree((ptr_t) now->word); 975: now->word = (Char *) xcalloc(1, (size_t) ((cmd_len + 2) * sizeof(Char))); 976: cp1 = now->word; 977: cp2 = cmd; 978: *cp1++ = '%'; 979: while (*cp1++ = *cp2++); 980: for (now = now->next; 981: *now->word != '\n' && *now->word != ';' && now != plist;) { 982: now->prev->next = now->next; 983: now->next->prev = now->prev; 984: xfree((ptr_t) now->word); 985: del = now; 986: now = now->next; 987: xfree((ptr_t) del); 988: } 989: } 990: } 991: 992: static void 993: insert_we(new, where) 994: struct wordent *new, *where; 995: { 996: 997: new->prev = where; 998: new->next = where->next; 999: where->next = new; 1000: new->next->prev = new; 1001: } 1002: 1003: static int 1004: inlist(list, name) 1005: Char *list, *name; 1006: { 1007: register Char *l, *n; 1008: 1009: l = list; 1010: n = name; 1011: 1012: while (*l && *n) { 1013: if (*l == *n) { 1014: l++; 1015: n++; 1016: if (*n == '\0' && (*l == ' ' || *l == '\0')) 1017: return (1); 1018: else 1019: continue; 1020: } 1021: else { 1022: while (*l && *l != ' ') 1023: l++; /* skip to blank */ 1024: while (*l && *l == ' ') 1025: l++; /* and find first nonblank character */ 1026: n = name; 1027: } 1028: } 1029: return (0); 1030: } 1031: 1032: #endif /* BSDJOBS */ 1033: 1034: 1035: /* 1036: * Implement a small cache for tilde names. This is used primarily 1037: * to expand tilde names to directories, but also 1038: * we can find users from their home directories for the tilde 1039: * prompt, on machines where yp lookup is slow this can be a big win... 1040: * As with any cache this can run out of sync... 1041: */ 1042: static struct tildecache { 1043: Char *user; 1044: Char *home; 1045: int hlen; 1046: } *tcache = NULL; 1047: 1048: #define TILINCR 10 1049: static int tlength = 0, tsize = TILINCR; 1050: 1051: static int 1052: tildecompare(p1, p2) 1053: struct tildecache *p1, *p2; 1054: { 1055: return Strcmp(p1->user, p2->user); 1056: } 1057: 1058: Char * 1059: gettilde(us) 1060: Char *us; 1061: { 1062: struct tildecache *bp1, *bp2, *bp; 1063: register struct passwd *pp; 1064: 1065: if (tcache == NULL) 1066: tcache = (struct tildecache *) xmalloc((size_t) (TILINCR * 1067: sizeof(struct tildecache))); 1068: /* 1069: * Binary search 1070: */ 1071: for (bp1 = tcache, bp2 = tcache + tlength; bp1 < bp2;) { 1072: register int i; 1073: 1074: bp = bp1 + ((bp2 - bp1) >> 1); 1075: if ((i = *us - *bp->user) == 0 && (i = Strcmp(us, bp->user)) == 0) 1076: return (bp->home); 1077: if (i < 0) 1078: bp2 = bp; 1079: else 1080: bp1 = bp + 1; 1081: } 1082: /* 1083: * Not in the cache, try to get it from the passwd file 1084: */ 1085: pp = getpwnam(short2str(us)); 1086: #ifdef YPBUGS 1087: fix_yp_bugs(); 1088: #endif 1089: if (pp == NULL) 1090: return NULL; 1091: 1092: /* 1093: * Update the cache 1094: */ 1095: tcache[tlength].user = Strsave(us); 1096: us = tcache[tlength].home = Strsave(str2short(pp->pw_dir)); 1097: tcache[tlength++].hlen = Strlen(us); 1098: 1099: (void) qsort((ptr_t) tcache, (size_t) tlength, sizeof(struct tildecache), 1100: tildecompare); 1101: 1102: if (tlength == tsize) { 1103: tsize += TILINCR; 1104: tcache = (struct tildecache *) xrealloc((ptr_t) tcache, 1105: (size_t) (tsize * 1106: sizeof(struct tildecache))); 1107: } 1108: return (us); 1109: } 1110: 1111: /* 1112: * Return the username if the directory path passed contains a 1113: * user's home directory in the tilde cache, otherwise return NULL 1114: * hm points to the place where the path became different. 1115: * Special case: Our own home directory. 1116: */ 1117: Char * 1118: getusername(hm) 1119: Char **hm; 1120: { 1121: Char *h, *p; 1122: int i, j; 1123: 1124: if (((h = value(STRhome)) != NULL) && 1125: (Strncmp(p = *hm, h, j = Strlen(h)) == 0) && 1126: (p[j] == '/' || p[j] == '\0')) { 1127: *hm = &p[j]; 1128: return STRNULL; 1129: } 1130: for (i = 0; i < tlength; i++) 1131: if ((Strncmp(p = *hm, tcache[i].home, j = tcache[i].hlen) == 0) && 1132: (p[j] == '/' || p[j] == '\0')) { 1133: *hm = &p[j]; 1134: return tcache[i].user; 1135: } 1136: return NULL; 1137: } 1138: 1139: /* 1140: * PWP: read a bunch of aliases out of a file QUICKLY. The format 1141: * is almost the same as the result of saying "alias > FILE", except 1142: * that saying "aliases > FILE" does not expand non-letters to printable 1143: * sequences. 1144: */ 1145: void 1146: do_aliases(v) 1147: Char **v; 1148: { 1149: jmp_buf oldexit; 1150: Char **vec, *lp; 1151: int fd; 1152: Char buf[BUFSIZ], line[BUFSIZ]; 1153: char tbuf[BUFSIZ + 1], *tmp; 1154: extern bool output_raw; /* PWP: in sh.print.c */ 1155: 1156: v++; 1157: if (*v == 0) { 1158: output_raw = 1; 1159: plist(&aliases); 1160: output_raw = 0; 1161: return; 1162: } 1163: 1164: gflag = 0, tglob(v); 1165: if (gflag) { 1166: v = globall(v); 1167: if (v == 0) 1168: stderror(ERR_NAME | ERR_NOMATCH); 1169: } 1170: else { 1171: v = gargv = saveblk(v); 1172: trim(v); 1173: } 1174: 1175: if ((fd = open(tmp = short2str(*v), O_RDONLY)) < 0) 1176: stderror(ERR_NAME | ERR_SYSTEM, tmp, strerror(errno)); 1177: 1178: getexit(oldexit); 1179: if (setexit() == 0) { 1180: for (;;) { 1181: lp = line; 1182: for (;;) { 1183: Char *p = NULL; 1184: int n = 0; 1185: if (n <= 0) { 1186: int i; 1187: 1188: if ((n = read(fd, tbuf, BUFSIZ)) <= 0) 1189: goto eof; 1190: for (i = 0; i < n; i++) 1191: buf[i] = tbuf[i]; 1192: p = buf; 1193: } 1194: n--; 1195: if ((*lp++ = *p++) == '\n') { 1196: lp[-1] = '\0'; 1197: break; 1198: } 1199: } 1200: for (lp = line; *lp; lp++) { 1201: if (isspc(*lp)) { 1202: *lp++ = '\0'; 1203: while (isspc(*lp)) 1204: lp++; 1205: vec = (Char **) xmalloc((size_t) 1206: (2 * sizeof(Char **))); 1207: vec[0] = Strsave(lp); 1208: vec[1] = NULL; 1209: setq(strip(line), vec, &aliases); 1210: break; 1211: } 1212: } 1213: } 1214: } 1215: 1216: eof: 1217: (void) close(fd); 1218: tw_clear_comm_list(); 1219: if (gargv) 1220: blkfree(gargv), gargv = 0; 1221: resexit(oldexit); 1222: }