/* $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 $ */ /* * tc.func.c: New tcsh builtins. */ /*- * Copyright (c) 1980, 1991 The Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "config.h" #if !defined(lint) && !defined(pdp11) static char *rcsid() { return "$Id: tc.func.c,v 3.0 1991/07/04 21:49:28 christos Exp $"; } #endif #include "sh.h" #include "ed.h" #include "ed.defns.h" /* for the function names */ #include "tw.h" extern time_t t_period; static bool precmd_active = 0; static bool periodic_active = 0; static bool cwdcmd_active = 0; /* PWP: for cwd_cmd */ static void Reverse __P((Char *)); static void auto_logout __P((void)); static void insert __P((struct wordent *, bool)); static void insert_we __P((struct wordent *, struct wordent *)); static int inlist __P((Char *, Char *)); /* * Tops-C shell */ /* * expand_lex: Take the given lex and put an expanded version of it in the * string buf. First guy in lex list is ignored; last guy is ^J which we * ignore Only take lex'es from position from to position to inclusive Note: * csh sometimes sets bit 8 in characters which causes all kinds of problems * if we don't mask it here. Note: excl's in lexes have been un-back-slashed * and must be re-back-slashed * (PWP: NOTE: this returns a pointer to the END of the string expanded * (in other words, where the NUL is).) */ /* PWP: this is a combination of the old sprlex() and the expand_lex from the magic-space stuff */ Char * expand_lex(buf, bufsiz, sp0, from, to) Char *buf; int bufsiz; struct wordent *sp0; int from, to; { register struct wordent *sp; register Char *s, *d, *e; register Char prev_c; register int i; buf[0] = '\0'; prev_c = '\0'; d = buf; e = &buf[bufsiz]; /* for bounds checking */ if (!sp0) return (buf); /* null lex */ if ((sp = sp0->next) == sp0) return (buf); /* nada */ if (sp == (sp0 = sp0->prev)) return (buf); /* nada */ for (i = 0; i < NCARGS; i++) { if ((i >= from) && (i <= to)) { /* if in range */ for (s = sp->word; *s && d < e; s++) { /* * bugfix by Michael Bloom: anything but the current history * character {(PWP) and backslash} seem to be dealt with * elsewhere. */ if ((*s & QUOTE) && (((*s & TRIM) == HIST) || ((*s & TRIM) == '\\') && (prev_c != '\\'))) { *d++ = '\\'; } *d++ = (*s & TRIM); prev_c = *s; } if (d < e) *d++ = ' '; } sp = sp->next; if (sp == sp0) break; } if (d > buf) d--; /* get rid of trailing space */ return (d); } Char * sprlex(buf, sp0) Char *buf; struct wordent *sp0; { Char *cp; cp = expand_lex(buf, INBUFSIZ, sp0, 0, NCARGS); *cp = '\0'; return (buf); } void Itoa(n, s) /* convert n to characters in s */ int n; Char *s; { int i, sign; if ((sign = n) < 0) /* record sign */ n = -n; i = 0; do { s[i++] = n % 10 + '0'; } while ((n /= 10) > 0); if (sign < 0) s[i++] = '-'; s[i] = '\0'; Reverse(s); } static void Reverse(s) Char *s; { int c, i, j; for (i = 0, j = Strlen(s) - 1; i < j; i++, j--) { c = s[i]; s[i] = s[j]; s[j] = c; } } void dolist(v) register Char **v; { int i, k; struct stat st; if (*++v == NULL) { (void) t_search(STRNULL, NULL, LIST, 0, 0, 0); return; } gflag = 0; tglob(v); if (gflag) { v = globall(v); if (v == 0) stderror(ERR_NAME | ERR_NOMATCH); } else v = gargv = saveblk(v); trim(v); for (k = 0; v[k] != NULL && v[k][0] != '-'; k++); if (v[k]) { /* * We cannot process a flag therefore we let ls do it right. */ static Char STRls[] = {'l', 's', '\0'}; static Char STRmCF[] = {'-', 'C', 'F', '\0'}; struct command *t; struct wordent cmd, *nextword, *lastword; Char *cp; #ifdef BSDSIGS sigmask_t omask = 0; if (setintr) omask = sigblock(sigmask(SIGINT)) & ~sigmask(SIGINT); #else sighold(SIGINT); #endif if (seterr) { xfree((ptr_t) seterr); seterr = NULL; } cmd.word = STRNULL; lastword = &cmd; nextword = (struct wordent *) xcalloc(1, sizeof cmd); nextword->word = Strsave(STRls); lastword->next = nextword; nextword->prev = lastword; lastword = nextword; nextword = (struct wordent *) xcalloc(1, sizeof cmd); nextword->word = Strsave(STRmCF); lastword->next = nextword; nextword->prev = lastword; lastword = nextword; for (cp = *v; cp; cp = *++v) { nextword = (struct wordent *) xcalloc(1, sizeof cmd); nextword->word = Strsave(cp); lastword->next = nextword; nextword->prev = lastword; lastword = nextword; } lastword->next = &cmd; cmd.prev = lastword; /* build a syntax tree for the command. */ t = syntax(cmd.next, &cmd, 0); if (seterr) stderror(ERR_OLD); /* expand aliases like process() does */ /* alias(&cmd); */ /* execute the parse tree. */ execute(t, tpgrp > 0 ? tpgrp : -1, NULL, NULL); /* done. free the lex list and parse tree. */ freelex(&cmd), freesyn(t); if (setintr) #ifdef BSDSIGS (void) sigsetmask(omask); #else (void) sigrelse(SIGINT); #endif } else { Char *dp, *tmp, buf[MAXPATHLEN]; for (k = 0, i = 0; v[k] != NULL; k++) { tmp = dnormalize(v[k]); dp = &tmp[Strlen(tmp) - 1]; if (*dp == '/' && dp != tmp) #ifdef apollo if (dp != &tmp[1]) #endif *dp = '\0'; if (stat(short2str(tmp), &st) == -1) { if (k != i) { if (i != 0) xputchar('\n'); print_by_column(STRNULL, &v[i], k - i, FALSE); } xprintf("%s: %s.\n", short2str(tmp), strerror(errno)); i = k + 1; } else if (S_ISDIR(st.st_mode)) { Char *cp; if (k != i) { if (i != 0) xputchar('\n'); print_by_column(STRNULL, &v[i], k - i, FALSE); } if (k != 0 && v[1] != NULL) xputchar('\n'); xprintf("%s:\n", short2str(tmp)); for (cp = tmp, dp = buf; *cp; *dp++ = (*cp++ | QUOTE)); if (dp[-1] != (Char) ('/' | QUOTE)) *dp++ = '/'; else dp[-1] &= TRIM; *dp = '\0'; (void) t_search(buf, NULL, LIST, 0, 0, 0); i = k + 1; } xfree((ptr_t) tmp); } if (k != i) { if (i != 0) xputchar('\n'); print_by_column(STRNULL, &v[i], k - i, FALSE); } } if (gargv) { blkfree(gargv); gargv = 0; } } static char *d_tell = "ALL"; extern bool GotTermCaps; void dotelltc(v) register Char **v; { if (!GotTermCaps) GetTermCaps(); TellTC(v[1] ? short2str(v[1]) : d_tell); } void doechotc(v) register Char **v; { if (!GotTermCaps) GetTermCaps(); EchoTC(++v); } void dosettc(v) Char **v; { char tv[2][BUFSIZ]; if (!GotTermCaps) GetTermCaps(); (void) strcpy(tv[0], short2str(v[1])); (void) strcpy(tv[1], short2str(v[2])); SetTC(tv[0], tv[1]); } /* The dowhich() is by: * Andreas Luik * I S A GmbH - Informationssysteme fuer computerintegrierte Automatisierung * Azenberstr. 35 * D-7000 Stuttgart 1 * West-Germany * Thanks!! */ void dowhich(v) register Char **v; { struct wordent lex[3]; struct varent *vp; lex[0].next = &lex[1]; lex[1].next = &lex[2]; lex[2].next = &lex[0]; lex[0].prev = &lex[2]; lex[1].prev = &lex[0]; lex[2].prev = &lex[1]; lex[0].word = STRNULL; lex[2].word = STRret; while (*++v) { if (vp = adrof1(*v, &aliases)) { xprintf("%s: \t aliased to ", short2str(*v)); blkpr(vp->vec); xprintf("\n"); } else { lex[1].word = *v; tellmewhat(lex); } } } /* PWP: a hack to start up your stopped editor on a single keystroke */ /* jbs - fixed hack so it worked :-) 3/28/89 */ struct process * find_stop_ed() { register struct process *pp; register char *ep, *vp, *p; int epl, vpl; if ((ep = getenv("EDITOR")) != NULL) { /* if we have a value */ if ((p = strrchr(ep, '/')) != NULL) { /* if it has a path */ ep = p + 1; /* then we want only the last part */ } } else { ep = "ed"; } if ((vp = getenv("VISUAL")) != NULL) { /* if we have a value */ if ((p = strrchr(vp, '/')) != NULL) { /* and it has a path */ vp = p + 1; /* then we want only the last part */ } } else { vp = "vi"; } vpl = strlen(vp); epl = strlen(ep); if (pcurrent == PNULL) /* see if we have any jobs */ return PNULL; /* nope */ for (pp = proclist.p_next; pp; pp = pp->p_next) { if (pp->p_pid == pp->p_jobid) { p = short2str(pp->p_command); /* if we find either in the current name, fg it */ if (strncmp(ep, p, (size_t) epl) == 0 || strncmp(vp, p, (size_t) vpl) == 0) return pp; } } return PNULL; /* didn't find a job */ } void fg_proc_entry(pp) register struct process *pp; { #ifdef BSDSIGS sigmask_t omask; #endif jmp_buf osetexit; bool ohaderr; getexit(osetexit); #ifdef BSDSIGS omask = sigblock(sigmask(SIGINT)); #else (void) sighold(SIGINT); #endif ohaderr = haderr; /* we need to ignore setting of haderr due to * process getting stopped by a signal */ if (setexit() == 0) { /* come back here after pjwait */ pendjob(); pstart(pp, 1); /* found it. */ pjwait(pp); } resexit(osetexit); haderr = ohaderr; #ifdef BSDSIGS (void) sigsetmask(omask); #else (void) sigrelse(SIGINT); #endif } static void auto_logout() { xprintf("auto-logout\n"); /* Don't leave the tty in raw mode */ if (editing) (void) Cookedmode(); (void) close(SHIN); set(STRlogout, Strsave(STRa_matic)); child = 1; #ifdef TESLA do_logout = 1; #endif /* TESLA */ goodbye(); } sigret_t /*ARGSUSED*/ alrmcatch(snum) int snum; { time_t cl, nl; if ((nl = sched_next()) == -1) auto_logout(); /* no other possibility - logout */ (void) time(&cl); if (nl <= cl + 1) sched_run(); else auto_logout(); setalarm(); #ifndef SIGVOID return (snum); #endif } /* * Karl Kleinpaste, 21oct1983. * Added precmd(), which checks for the alias * precmd in aliases. If it's there, the alias * is executed as a command. This is done * after mailchk() and just before print- * ing the prompt. Useful for things like printing * one's current directory just before each command. */ void precmd() { #ifdef BSDSIGS sigmask_t omask; #endif #ifdef BSDSIGS omask = sigblock(sigmask(SIGINT)); #else (void) sighold(SIGINT); #endif if (precmd_active) { /* an error must have been caught */ aliasrun(2, STRunalias, STRprecmd); xprintf("Faulty alias 'precmd' removed.\n"); goto leave; } precmd_active = 1; if (!whyles && adrof1(STRprecmd, &aliases)) aliasrun(1, STRprecmd, NULL); leave: precmd_active = 0; #ifdef BSDSIGS (void) sigsetmask(omask); #else (void) sigrelse(SIGINT); #endif } /* * Paul Placeway 11/24/87 Added cwd_cmd by hacking precmd() into * submission... Run every time $cwd is set (after it is set). Useful * for putting your machine and cwd (or anything else) in an xterm title * space. */ void cwd_cmd() { #ifdef BSDSIGS sigmask_t omask; #endif #ifdef BSDSIGS omask = sigblock(sigmask(SIGINT)); #else (void) sighold(SIGINT); #endif if (cwdcmd_active) { /* an error must have been caught */ aliasrun(2, STRunalias, STRcwdcmd); xprintf("Faulty alias 'cwdcmd' removed.\n"); goto leave; } cwdcmd_active = 1; if (!whyles && adrof1(STRcwdcmd, &aliases)) aliasrun(1, STRcwdcmd, NULL); leave: cwdcmd_active = 0; #ifdef BSDSIGS (void) sigsetmask(omask); #else (void) sigrelse(SIGINT); #endif } /* * Karl Kleinpaste, 18 Jan 1984. * Added period_cmd(), which executes the alias "periodic" every * $tperiod minutes. Useful for occasional checking of msgs and such. */ void period_cmd() { register Char *vp; time_t t, interval; #ifdef BSDSIGS sigmask_t omask; #endif #ifdef BSDSIGS omask = sigblock(sigmask(SIGINT)); #else (void) sighold(SIGINT); #endif if (periodic_active) { /* an error must have been caught */ aliasrun(2, STRunalias, STRperiodic); xprintf("Faulty alias 'periodic' removed.\n"); goto leave; } periodic_active = 1; if (!whyles && adrof1(STRperiodic, &aliases)) { vp = value(STRtperiod); if (vp == NOSTR) return; interval = getn(vp); (void) time(&t); if (t - t_period >= interval * 60) { t_period = t; aliasrun(1, STRperiodic, NULL); } } leave: periodic_active = 0; #ifdef BSDSIGS (void) sigsetmask(omask); #else (void) sigrelse(SIGINT); #endif } /* * Karl Kleinpaste, 21oct1983. * Set up a one-word alias command, for use for special things. * This code is based on the mainline of process(). */ void aliasrun(cnt, s1, s2) int cnt; Char *s1, *s2; { struct wordent w, *new1, *new2; /* for holding alias name */ struct command *t = NULL; jmp_buf osetexit; getexit(osetexit); if (seterr) { xfree((ptr_t) seterr); seterr = NULL; /* don't repeatedly print err msg. */ } w.word = STRNULL; new1 = (struct wordent *) xcalloc(1, sizeof w); new1->word = Strsave(s1); if (cnt == 1) { /* build a lex list with one word. */ w.next = w.prev = new1; new1->next = new1->prev = &w; } else { /* build a lex list with two words. */ new2 = (struct wordent *) xcalloc(1, sizeof w); new2->word = Strsave(s2); w.next = new2->prev = new1; new1->next = w.prev = new2; new1->prev = new2->next = &w; } /* expand aliases like process() does. */ alias(&w); /* build a syntax tree for the command. */ t = syntax(w.next, &w, 0); if (seterr) stderror(ERR_OLD); psavejob(); /* catch any errors here */ if (setexit() == 0) /* execute the parse tree. */ /* * From: Michael Schroeder * was execute(t, tpgrp); */ execute(t, tpgrp > 0 ? tpgrp : -1, NULL, NULL); /* done. free the lex list and parse tree. */ freelex(&w), freesyn(t); if (haderr) { haderr = 0; /* * Either precmd, or cwdcmd, or periodic had an error. Call it again so * that it is removed */ if (precmd_active) precmd(); #ifdef notdef /* * XXX: On the other hand, just interrupting them causes an error too. * So if we hit ^C in the middle of cwdcmd or periodic the alias gets * removed. We don't want that. Note that we want to remove precmd * though, cause that could lead into an infinite loop. This should be * fixed correctly, but then haderr should give us the whole exit * status not just true or false. */ else if (cwdcmd_active) cwd_cmd(); else if (periodic_active) period_cmd(); #endif } /* reset the error catcher to the old place */ resexit(osetexit); prestjob(); pendjob(); } void setalarm() { struct varent *vp; Char *cp; unsigned alrm_time = 0; long cl, nl, sched_dif; if (vp = adrof(STRa_logout)) { if (cp = vp->vec[0]) alrm_time = (atoi(short2str(cp)) * 60); } if ((nl = sched_next()) != -1) { (void) time(&cl); sched_dif = nl - cl; if ((alrm_time == 0) || (sched_dif < alrm_time)) alrm_time = ((int) sched_dif) + 1; } (void) alarm(alrm_time); /* Autologout ON */ } #define RMDEBUG /* For now... */ void rmstar(cp) struct wordent *cp; { struct wordent *we, *args; register struct wordent *tmp, *del; #ifdef RMDEBUG static Char STRrmdebug[] = {'r', 'm', 'd', 'e', 'b', 'u', 'g', '\0'}; Char *tag; #endif Char *charac; char c; int ask, doit, star = 0, silent = 0; if (!adrof(STRrmstar)) return; #ifdef RMDEBUG tag = value(STRrmdebug); #endif we = cp->next; while (*we->word == ';' && we != cp) we = we->next; while (we != cp) { #ifdef RMDEBUG if (*tag) xprintf("parsing command line\n"); #endif if (!Strcmp(we->word, STRrm)) { args = we->next; ask = (*args->word != '-'); while (*args->word == '-' && !silent) { /* check options */ for (charac = (args->word + 1); *charac && !silent; charac++) silent = (*charac == 'i' || *charac == 'f'); args = args->next; } ask = (ask || !ask && !silent); if (ask) { for (; !star && *args->word != ';' && args != cp; args = args->next) if (!Strcmp(args->word, STRstar)) star = 1; if (ask && star) { xprintf("Do you really want to delete all files? [n/y] "); flush(); (void) read(SHIN, &c, 1); doit = (c == 'Y' || c == 'y'); while (c != '\n') (void) read(SHIN, &c, 1); if (!doit) { /* remove the command instead */ if (*tag) xprintf("skipping deletion of files!\n"); for (tmp = we; *tmp->word != '\n' && *tmp->word != ';' && tmp != cp;) { tmp->prev->next = tmp->next; tmp->next->prev = tmp->prev; xfree((ptr_t) tmp->word); del = tmp; tmp = tmp->next; xfree((ptr_t) del); } if (*tmp->word == ';') { tmp->prev->next = tmp->next; tmp->next->prev = tmp->prev; xfree((ptr_t) tmp->word); del = tmp; xfree((ptr_t) del); } } } } } for (we = we->next; *we->word != ';' && we != cp; we = we->next); if (*we->word == ';') we = we->next; } #ifdef RMDEBUG if (*tag) { xprintf("command line now is:\n"); for (we = cp->next; we != cp; we = we->next) xprintf("%s ", short2str(we->word)); } #endif return; } #ifdef BSDJOBS /* Check if command is in continue list and do a "aliasing" if it exists as a job in background */ #define CNDEBUG /* For now */ void con_jobs(cp) struct wordent *cp; { struct wordent *we; register struct process *pp, *np; Char *cmd, *con_list, *con_args_list; #ifdef CNDEBUG Char *tag; static Char STRcndebug[] = {'c', 'n', 'd', 'e', 'b', 'u', 'g', '\0'}; #endif bool in_c__list, in_c__arg_list; #ifdef CNDEBUG tag = value(STRcndebug); #endif con_list = value(STRcontinue); con_args_list = value(STRcon_args); if (*con_list == '\0' && *con_args_list == '\0') return; we = cp->next; while (*we->word == ';' && we != cp) we = we->next; while (we != cp) { #ifdef CNDEBUG if (*tag) xprintf("parsing command line\n"); #endif cmd = we->word; in_c__list = inlist(con_list, cmd); in_c__arg_list = inlist(con_args_list, cmd); if (in_c__list || in_c__arg_list) { #ifdef CNDEBUG if (*tag) xprintf("in one of the lists\n"); #endif np = PNULL; for (pp = proclist.p_next; pp; pp = pp->p_next) { if (prefix(cmd, pp->p_command)) { if (pp->p_index) { np = pp; break; } } } if (np) { insert(we, in_c__arg_list); } } for (we = we->next; *we->word != ';' && we != cp; we = we->next); if (*we->word == ';') we = we->next; } #ifdef CNDEBUG if (*tag) { xprintf("command line now is:\n"); for (we = cp->next; we != cp; we = we->next) xprintf("%s ", short2str(we->word)); } #endif return; } /* The actual "aliasing" of for backgrounds() is done here with the aid of insert_we(). */ static void insert(plist, file_args) struct wordent *plist; bool file_args; { struct wordent *now, *last; Char *cmd, *bcmd, *cp1, *cp2; int cmd_len; Char *pause = STRunderpause; int p_len = Strlen(pause); cmd_len = Strlen(plist->word); cmd = (Char *) xcalloc(1, (size_t) ((cmd_len + 1) * sizeof(Char))); (void) Strcpy(cmd, plist->word); /* Do insertions at beginning, first replace command word */ if (file_args) { now = plist; xfree((ptr_t) now->word); now->word = (Char *) xcalloc(1, (size_t) (5 * sizeof(Char))); (void) Strcpy(now->word, STRecho); now = (struct wordent *) xcalloc(1, (size_t) sizeof(struct wordent)); now->word = (Char *) xcalloc(1, (size_t) (6 * sizeof(Char))); (void) Strcpy(now->word, STRbKqpwd); insert_we(now, plist); for (last = now; *last->word != '\n' && *last->word != ';'; last = last->next); now = (struct wordent *) xcalloc(1, (size_t) sizeof(struct wordent)); now->word = (Char *) xcalloc(1, (size_t) (2 * sizeof(Char))); (void) Strcpy(now->word, STRgt); insert_we(now, last->prev); now = (struct wordent *) xcalloc(1, (size_t) sizeof(struct wordent)); now->word = (Char *) xcalloc(1, (size_t) (2 * sizeof(Char))); (void) Strcpy(now->word, STRbang); insert_we(now, last->prev); now = (struct wordent *) xcalloc(1, (size_t) sizeof(struct wordent)); now->word = (Char *) xcalloc(1, (size_t) cmd_len + p_len + 4); cp1 = now->word; cp2 = cmd; *cp1++ = '~'; *cp1++ = '/'; *cp1++ = '.'; while (*cp1++ = *cp2++); cp1--; cp2 = pause; while (*cp1++ = *cp2++); insert_we(now, last->prev); now = (struct wordent *) xcalloc(1, (size_t) sizeof(struct wordent)); now->word = (Char *) xcalloc(1, (size_t) (2 * sizeof(Char))); (void) Strcpy(now->word, STRsm); insert_we(now, last->prev); bcmd = (Char *) xcalloc(1, (size_t) ((cmd_len + 2) * sizeof(Char))); cp1 = bcmd; cp2 = cmd; *cp1++ = '%'; while (*cp1++ = *cp2++); now = (struct wordent *) xcalloc(1, (size_t) (sizeof(struct wordent))); now->word = bcmd; insert_we(now, last->prev); } else { struct wordent *del; now = plist; xfree((ptr_t) now->word); now->word = (Char *) xcalloc(1, (size_t) ((cmd_len + 2) * sizeof(Char))); cp1 = now->word; cp2 = cmd; *cp1++ = '%'; while (*cp1++ = *cp2++); for (now = now->next; *now->word != '\n' && *now->word != ';' && now != plist;) { now->prev->next = now->next; now->next->prev = now->prev; xfree((ptr_t) now->word); del = now; now = now->next; xfree((ptr_t) del); } } } static void insert_we(new, where) struct wordent *new, *where; { new->prev = where; new->next = where->next; where->next = new; new->next->prev = new; } static int inlist(list, name) Char *list, *name; { register Char *l, *n; l = list; n = name; while (*l && *n) { if (*l == *n) { l++; n++; if (*n == '\0' && (*l == ' ' || *l == '\0')) return (1); else continue; } else { while (*l && *l != ' ') l++; /* skip to blank */ while (*l && *l == ' ') l++; /* and find first nonblank character */ n = name; } } return (0); } #endif /* BSDJOBS */ /* * Implement a small cache for tilde names. This is used primarily * to expand tilde names to directories, but also * we can find users from their home directories for the tilde * prompt, on machines where yp lookup is slow this can be a big win... * As with any cache this can run out of sync... */ static struct tildecache { Char *user; Char *home; int hlen; } *tcache = NULL; #define TILINCR 10 static int tlength = 0, tsize = TILINCR; static int tildecompare(p1, p2) struct tildecache *p1, *p2; { return Strcmp(p1->user, p2->user); } Char * gettilde(us) Char *us; { struct tildecache *bp1, *bp2, *bp; register struct passwd *pp; if (tcache == NULL) tcache = (struct tildecache *) xmalloc((size_t) (TILINCR * sizeof(struct tildecache))); /* * Binary search */ for (bp1 = tcache, bp2 = tcache + tlength; bp1 < bp2;) { register int i; bp = bp1 + ((bp2 - bp1) >> 1); if ((i = *us - *bp->user) == 0 && (i = Strcmp(us, bp->user)) == 0) return (bp->home); if (i < 0) bp2 = bp; else bp1 = bp + 1; } /* * Not in the cache, try to get it from the passwd file */ pp = getpwnam(short2str(us)); #ifdef YPBUGS fix_yp_bugs(); #endif if (pp == NULL) return NULL; /* * Update the cache */ tcache[tlength].user = Strsave(us); us = tcache[tlength].home = Strsave(str2short(pp->pw_dir)); tcache[tlength++].hlen = Strlen(us); (void) qsort((ptr_t) tcache, (size_t) tlength, sizeof(struct tildecache), tildecompare); if (tlength == tsize) { tsize += TILINCR; tcache = (struct tildecache *) xrealloc((ptr_t) tcache, (size_t) (tsize * sizeof(struct tildecache))); } return (us); } /* * Return the username if the directory path passed contains a * user's home directory in the tilde cache, otherwise return NULL * hm points to the place where the path became different. * Special case: Our own home directory. */ Char * getusername(hm) Char **hm; { Char *h, *p; int i, j; if (((h = value(STRhome)) != NULL) && (Strncmp(p = *hm, h, j = Strlen(h)) == 0) && (p[j] == '/' || p[j] == '\0')) { *hm = &p[j]; return STRNULL; } for (i = 0; i < tlength; i++) if ((Strncmp(p = *hm, tcache[i].home, j = tcache[i].hlen) == 0) && (p[j] == '/' || p[j] == '\0')) { *hm = &p[j]; return tcache[i].user; } return NULL; } /* * PWP: read a bunch of aliases out of a file QUICKLY. The format * is almost the same as the result of saying "alias > FILE", except * that saying "aliases > FILE" does not expand non-letters to printable * sequences. */ void do_aliases(v) Char **v; { jmp_buf oldexit; Char **vec, *lp; int fd; Char buf[BUFSIZ], line[BUFSIZ]; char tbuf[BUFSIZ + 1], *tmp; extern bool output_raw; /* PWP: in sh.print.c */ v++; if (*v == 0) { output_raw = 1; plist(&aliases); output_raw = 0; return; } gflag = 0, tglob(v); if (gflag) { v = globall(v); if (v == 0) stderror(ERR_NAME | ERR_NOMATCH); } else { v = gargv = saveblk(v); trim(v); } if ((fd = open(tmp = short2str(*v), O_RDONLY)) < 0) stderror(ERR_NAME | ERR_SYSTEM, tmp, strerror(errno)); getexit(oldexit); if (setexit() == 0) { for (;;) { lp = line; for (;;) { Char *p = NULL; int n = 0; if (n <= 0) { int i; if ((n = read(fd, tbuf, BUFSIZ)) <= 0) goto eof; for (i = 0; i < n; i++) buf[i] = tbuf[i]; p = buf; } n--; if ((*lp++ = *p++) == '\n') { lp[-1] = '\0'; break; } } for (lp = line; *lp; lp++) { if (isspc(*lp)) { *lp++ = '\0'; while (isspc(*lp)) lp++; vec = (Char **) xmalloc((size_t) (2 * sizeof(Char **))); vec[0] = Strsave(lp); vec[1] = NULL; setq(strip(line), vec, &aliases); break; } } } } eof: (void) close(fd); tw_clear_comm_list(); if (gargv) blkfree(gargv), gargv = 0; resexit(oldexit); }