home *** CD-ROM | disk | FTP | other *** search
/ The Fatted Calf / The Fatted Calf.iso / Unix / Shells / tcsh / Source / tc.func.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-02-21  |  37.6 KB  |  1,691 lines

  1. /* $Header: /u/christos/src/tcsh-6.03/RCS/tc.func.c,v 3.37 1992/10/27 16:18:15 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 "sh.h"
  38.  
  39. RCSID("$Id: tc.func.c,v 3.37 1992/10/27 16:18:15 christos Exp $")
  40.  
  41. #include "ed.h"
  42. #include "ed.defns.h"        /* for the function names */
  43. #include "tw.h"
  44. #include "tc.h"
  45.  
  46. #ifdef HESIOD
  47. # include <hesiod.h>
  48. #endif /* HESIOD */
  49.  
  50. extern time_t t_period;
  51. extern int do_logout;
  52. extern int just_signaled;
  53. static bool precmd_active = 0;
  54. static bool periodic_active = 0;
  55. static bool cwdcmd_active = 0;    /* PWP: for cwd_cmd */
  56. static bool beepcmd_active = 0;
  57. static void (*alm_fun)() = NULL;
  58.  
  59. static    void     Reverse    __P((Char *));
  60. static    void     auto_logout    __P((void));
  61. static    char    *xgetpass    __P((char *));
  62. static    void     auto_lock    __P((void));
  63. #ifdef BSDJOBS
  64. static    void     insert        __P((struct wordent *, bool));
  65. static    void     insert_we    __P((struct wordent *, struct wordent *));
  66. static    int     inlist        __P((Char *, Char *));
  67. #endif /* BSDJOBS */
  68. static  Char    *gethomedir    __P((Char *));
  69.  
  70. /*
  71.  * Tops-C shell
  72.  */
  73.  
  74. /*
  75.  * expand_lex: Take the given lex and put an expanded version of it in the
  76.  * string buf. First guy in lex list is ignored; last guy is ^J which we
  77.  * ignore Only take lex'es from position from to position to inclusive Note:
  78.  * csh sometimes sets bit 8 in characters which causes all kinds of problems
  79.  * if we don't mask it here. Note: excl's in lexes have been un-back-slashed
  80.  * and must be re-back-slashed
  81.  * (PWP: NOTE: this returns a pointer to the END of the string expanded
  82.  *             (in other words, where the NUL is).)
  83.  */
  84. /* PWP: this is a combination of the old sprlex() and the expand_lex from
  85.    the magic-space stuff */
  86.  
  87. Char   *
  88. expand_lex(buf, bufsiz, sp0, from, to)
  89.     Char   *buf;
  90.     int     bufsiz;
  91.     struct wordent *sp0;
  92.     int     from, to;
  93. {
  94.     register struct wordent *sp;
  95.     register Char *s, *d, *e;
  96.     register Char prev_c;
  97.     register int i;
  98.  
  99.     buf[0] = '\0';
  100.     prev_c = '\0';
  101.     d = buf;
  102.     e = &buf[bufsiz];        /* for bounds checking */
  103.  
  104.     if (!sp0)
  105.     return (buf);        /* null lex */
  106.     if ((sp = sp0->next) == sp0)
  107.     return (buf);        /* nada */
  108.     if (sp == (sp0 = sp0->prev))
  109.     return (buf);        /* nada */
  110.  
  111.     for (i = 0; i < NCARGS; i++) {
  112.     if ((i >= from) && (i <= to)) {    /* if in range */
  113.         for (s = sp->word; *s && d < e; s++) {
  114.         /*
  115.          * bugfix by Michael Bloom: anything but the current history
  116.          * character {(PWP) and backslash} seem to be dealt with
  117.          * elsewhere.
  118.          */
  119.         if ((*s & QUOTE)
  120.             && (((*s & TRIM) == HIST) ||
  121.             (((*s & TRIM) == '\'') && (prev_c != '\\')) ||
  122.             (((*s & TRIM) == '\"') && (prev_c != '\\')) ||
  123.             (((*s & TRIM) == '\\') && (prev_c != '\\')))) {
  124.             *d++ = '\\';
  125.         }
  126.         *d++ = (*s & TRIM);
  127.         prev_c = *s;
  128.         }
  129.         if (d < e)
  130.         *d++ = ' ';
  131.     }
  132.     sp = sp->next;
  133.     if (sp == sp0)
  134.         break;
  135.     }
  136.     if (d > buf)
  137.     d--;            /* get rid of trailing space */
  138.  
  139.     return (d);
  140. }
  141.  
  142. Char   *
  143. sprlex(buf, sp0)
  144.     Char   *buf;
  145.     struct wordent *sp0;
  146. {
  147.     Char   *cp;
  148.  
  149.     cp = expand_lex(buf, INBUFSIZE, sp0, 0, NCARGS);
  150.     *cp = '\0';
  151.     return (buf);
  152. }
  153.  
  154. void
  155. Itoa(n, s)            /* convert n to characters in s */
  156.     int     n;
  157.     Char   *s;
  158. {
  159.     int     i, sign;
  160.  
  161.     if ((sign = n) < 0)        /* record sign */
  162.     n = -n;
  163.     i = 0;
  164.     do {
  165.     s[i++] = n % 10 + '0';
  166.     } while ((n /= 10) > 0);
  167.     if (sign < 0)
  168.     s[i++] = '-';
  169.     s[i] = '\0';
  170.     Reverse(s);
  171. }
  172.  
  173. static void
  174. Reverse(s)
  175.     Char   *s;
  176. {
  177.     int     c, i, j;
  178.  
  179.     for (i = 0, j = Strlen(s) - 1; i < j; i++, j--) {
  180.     c = s[i];
  181.     s[i] = s[j];
  182.     s[j] = c;
  183.     }
  184. }
  185.  
  186.  
  187. /*ARGSUSED*/
  188. void
  189. dolist(v, c)
  190.     register Char **v;
  191.     struct command *c;
  192. {
  193.     int     i, k;
  194.     struct stat st;
  195.  
  196.     if (*++v == NULL) {
  197.     (void) t_search(STRNULL, NULL, LIST, 0, TW_ZERO, 0, STRNULL, 0);
  198.     return;
  199.     }
  200.     gflag = 0;
  201.     tglob(v);
  202.     if (gflag) {
  203.     v = globall(v);
  204.     if (v == 0)
  205.         stderror(ERR_NAME | ERR_NOMATCH);
  206.     }
  207.     else
  208.     v = gargv = saveblk(v);
  209.     trim(v);
  210.     for (k = 0; v[k] != NULL && v[k][0] != '-'; k++)
  211.     continue;
  212.     if (v[k]) {
  213.     /*
  214.      * We cannot process a flag therefore we let ls do it right.
  215.      */
  216.     static Char STRls[] = {'l', 's', '\0'};
  217.     static Char STRmCF[] = {'-', 'C', 'F', '\0'};
  218.     struct command *t;
  219.     struct wordent cmd, *nextword, *lastword;
  220.     Char   *cp;
  221.  
  222. #ifdef BSDSIGS
  223.     sigmask_t omask = 0;
  224.  
  225.     if (setintr)
  226.         omask = sigblock(sigmask(SIGINT)) & ~sigmask(SIGINT);
  227. #else /* !BSDSIGS */
  228.     sighold(SIGINT);
  229. #endif /* BSDSIGS */
  230.     if (seterr) {
  231.         xfree((ptr_t) seterr);
  232.         seterr = NULL;
  233.     }
  234.     cmd.word = STRNULL;
  235.     lastword = &cmd;
  236.     nextword = (struct wordent *) xcalloc(1, sizeof cmd);
  237.     nextword->word = Strsave(STRls);
  238.     lastword->next = nextword;
  239.     nextword->prev = lastword;
  240.     lastword = nextword;
  241.     nextword = (struct wordent *) xcalloc(1, sizeof cmd);
  242.     nextword->word = Strsave(STRmCF);
  243.     lastword->next = nextword;
  244.     nextword->prev = lastword;
  245.     lastword = nextword;
  246.     for (cp = *v; cp; cp = *++v) {
  247.         nextword = (struct wordent *) xcalloc(1, sizeof cmd);
  248.         nextword->word = Strsave(cp);
  249.         lastword->next = nextword;
  250.         nextword->prev = lastword;
  251.         lastword = nextword;
  252.     }
  253.     lastword->next = &cmd;
  254.     cmd.prev = lastword;
  255.  
  256.     /* build a syntax tree for the command. */
  257.     t = syntax(cmd.next, &cmd, 0);
  258.     if (seterr)
  259.         stderror(ERR_OLD);
  260.     /* expand aliases like process() does */
  261.     /* alias(&cmd); */
  262.     /* execute the parse tree. */
  263.     execute(t, tpgrp > 0 ? tpgrp : -1, NULL, NULL);
  264.     /* done. free the lex list and parse tree. */
  265.     freelex(&cmd), freesyn(t);
  266.     if (setintr)
  267. #ifdef BSDSIGS
  268.         (void) sigsetmask(omask);
  269. #else /* !BSDSIGS */
  270.         (void) sigrelse(SIGINT);
  271. #endif /* BSDSIGS */
  272.     }
  273.     else {
  274.     Char   *dp, *tmp, buf[MAXPATHLEN];
  275.  
  276.     for (k = 0, i = 0; v[k] != NULL; k++) {
  277.         tmp = dnormalize(v[k], symlinks == SYM_IGNORE);
  278.         dp = &tmp[Strlen(tmp) - 1];
  279.         if (*dp == '/' && dp != tmp)
  280. #ifdef apollo
  281.         if (dp != &tmp[1])
  282. #endif /* apollo */
  283.         *dp = '\0';
  284.         if (stat(short2str(tmp), &st) == -1) {
  285.         if (k != i) {
  286.             if (i != 0)
  287.             xputchar('\n');
  288.             print_by_column(STRNULL, &v[i], k - i, FALSE);
  289.         }
  290.         xprintf("%S: %s.\n", tmp, strerror(errno));
  291.         i = k + 1;
  292.         }
  293.         else if (S_ISDIR(st.st_mode)) {
  294.         Char   *cp;
  295.  
  296.         if (k != i) {
  297.             if (i != 0)
  298.             xputchar('\n');
  299.             print_by_column(STRNULL, &v[i], k - i, FALSE);
  300.         }
  301.         if (k != 0 && v[1] != NULL)
  302.             xputchar('\n');
  303.         xprintf("%S:\n", tmp);
  304.         for (cp = tmp, dp = buf; *cp; *dp++ = (*cp++ | QUOTE))
  305.             continue;
  306.         if (dp[-1] != (Char) ('/' | QUOTE))
  307.             *dp++ = '/';
  308.         else 
  309.             dp[-1] &= TRIM;
  310.         *dp = '\0';
  311.         (void) t_search(buf, NULL, LIST, 0, TW_ZERO, 0, STRNULL, 0);
  312.         i = k + 1;
  313.         }
  314.         xfree((ptr_t) tmp);
  315.     }
  316.     if (k != i) {
  317.         if (i != 0)
  318.         xputchar('\n');
  319.         print_by_column(STRNULL, &v[i], k - i, FALSE);
  320.     }
  321.     }
  322.  
  323.     if (gargv) {
  324.     blkfree(gargv);
  325.     gargv = 0;
  326.     }
  327. }
  328.  
  329. static char *defaulttell = "ALL";
  330. extern bool GotTermCaps;
  331.  
  332. /*ARGSUSED*/
  333. void
  334. dotelltc(v, c)
  335.     register Char **v;
  336.     struct command *c;
  337. {
  338.  
  339.     if (!GotTermCaps)
  340.     GetTermCaps();
  341.  
  342.     TellTC(v[1] ? short2str(v[1]) : defaulttell);
  343. }
  344.  
  345. /*ARGSUSED*/
  346. void
  347. doechotc(v, c)
  348.     register Char **v;
  349.     struct command *c;
  350. {
  351.     if (!GotTermCaps)
  352.     GetTermCaps();
  353.     EchoTC(++v);
  354. }
  355.  
  356. /*ARGSUSED*/
  357. void
  358. dosettc(v, c)
  359.     Char  **v;
  360.     struct command *c;
  361. {
  362.     char    tv[2][BUFSIZE];
  363.  
  364.     if (!GotTermCaps)
  365.     GetTermCaps();
  366.  
  367.     (void) strcpy(tv[0], short2str(v[1]));
  368.     (void) strcpy(tv[1], short2str(v[2]));
  369.     SetTC(tv[0], tv[1]);
  370. }
  371.  
  372. /* The dowhich() is by:
  373.  *  Andreas Luik <luik@isaak.isa.de>
  374.  *  I S A  GmbH - Informationssysteme fuer computerintegrierte Automatisierung
  375.  *  Azenberstr. 35
  376.  *  D-7000 Stuttgart 1
  377.  *  West-Germany
  378.  * Thanks!!
  379.  */
  380.  
  381. /*ARGSUSED*/
  382. void
  383. dowhich(v, c)
  384.     register Char **v;
  385.     struct command *c;
  386. {
  387.     struct wordent lex[3];
  388.     struct varent *vp;
  389.  
  390.     lex[0].next = &lex[1];
  391.     lex[1].next = &lex[2];
  392.     lex[2].next = &lex[0];
  393.  
  394.     lex[0].prev = &lex[2];
  395.     lex[1].prev = &lex[0];
  396.     lex[2].prev = &lex[1];
  397.  
  398.     lex[0].word = STRNULL;
  399.     lex[2].word = STRret;
  400.  
  401.     gflag = 0, tglob(v);
  402.     if (gflag) {
  403.     v = globall(v);
  404.     if (v == 0)
  405.         stderror(ERR_NAME | ERR_NOMATCH);
  406.     }
  407.     else {
  408.     v = gargv = saveblk(v);
  409.     trim(v);
  410.     }
  411.  
  412.     while (*++v) {
  413.     if ((vp = adrof1(*v, &aliases)) != NULL) {
  414.         xprintf("%S: \t aliased to ", *v);
  415.         blkpr(vp->vec);
  416.         xputchar('\n');
  417.     }
  418.     else {
  419.         lex[1].word = *v;
  420.         tellmewhat(lex);
  421.     }
  422.     }
  423.     if (gargv)
  424.     blkfree(gargv), gargv = 0;
  425. }
  426.  
  427. /* PWP: a hack to start up your stopped editor on a single keystroke */
  428. /* jbs - fixed hack so it worked :-) 3/28/89 */
  429.  
  430. struct process *
  431. find_stop_ed()
  432. {
  433.     register struct process *pp;
  434.     register char *ep, *vp, *cp, *p;
  435.     int     epl, vpl;
  436.  
  437.     if ((ep = getenv("EDITOR")) != NULL) {    /* if we have a value */
  438.     if ((p = strrchr(ep, '/')) != NULL)     /* if it has a path */
  439.         ep = p + 1;        /* then we want only the last part */
  440.     }
  441.     else 
  442.     ep = "ed";
  443.  
  444.     if ((vp = getenv("VISUAL")) != NULL) {    /* if we have a value */
  445.     if ((p = strrchr(vp, '/')) != NULL)     /* and it has a path */
  446.         vp = p + 1;        /* then we want only the last part */
  447.     }
  448.     else 
  449.     vp = "vi";
  450.  
  451.     vpl = strlen(vp);
  452.     epl = strlen(ep);
  453.  
  454.     if (pcurrent == NULL)    /* see if we have any jobs */
  455.     return NULL;        /* nope */
  456.  
  457.     for (pp = proclist.p_next; pp; pp = pp->p_next)
  458.     if (pp->p_procid == pp->p_jobid) {
  459.         p = short2str(pp->p_command);
  460.         /* get the first word */
  461.         for (cp = p; *cp && !isspace(*cp); cp++)
  462.         continue;
  463.         *cp = '\0';
  464.         
  465.         if ((cp = strrchr(p, '/')) != NULL)    /* and it has a path */
  466.         cp = cp + 1;        /* then we want only the last part */
  467.         else
  468.         cp = p;            /* else we get all of it */
  469.  
  470.         /* if we find either in the current name, fg it */
  471.         if (strncmp(ep, cp, (size_t) epl) == 0 ||
  472.         strncmp(vp, cp, (size_t) vpl) == 0)
  473.         return pp;
  474.     }
  475.  
  476.     return NULL;        /* didn't find a job */
  477. }
  478.  
  479. void
  480. fg_proc_entry(pp)
  481.     register struct process *pp;
  482. {
  483. #ifdef BSDSIGS
  484.     sigmask_t omask;
  485. #endif
  486.     jmp_buf_t osetexit;
  487.     bool    ohaderr;
  488.     bool    oGettingInput;
  489.  
  490.     getexit(osetexit);
  491.  
  492. #ifdef BSDSIGS
  493.     omask = sigblock(sigmask(SIGINT));
  494. #else
  495.     (void) sighold(SIGINT);
  496. #endif
  497.     oGettingInput = GettingInput;
  498.     GettingInput = 0;
  499.  
  500.     ohaderr = haderr;        /* we need to ignore setting of haderr due to
  501.                  * process getting stopped by a signal */
  502.     if (setexit() == 0) {    /* come back here after pjwait */
  503.     pendjob();
  504.     pstart(pp, 1);        /* found it. */
  505.     alarm(0);        /* No autologout */
  506.     pjwait(pp);
  507.     }
  508.     setalarm(1);        /* Autologout back on */
  509.     resexit(osetexit);
  510.     haderr = ohaderr;
  511.     GettingInput = oGettingInput;
  512.  
  513. #ifdef BSDSIGS
  514.     (void) sigsetmask(omask);
  515. #else /* !BSDSIGS */
  516.     (void) sigrelse(SIGINT);
  517. #endif /* BSDSIGS */
  518.  
  519. }
  520.  
  521. static char *
  522. xgetpass(prm)
  523.     char *prm;
  524. {
  525.     static char pass[9];
  526.     int fd, i;
  527.     sigret_t (*sigint)();
  528.  
  529.     sigint = (sigret_t (*)()) sigset(SIGINT, SIG_IGN);
  530.     (void) Rawmode();    /* Make sure, cause we want echo off */
  531.     if ((fd = open("/dev/tty", O_RDWR)) == -1)
  532.     fd = SHIN;
  533.  
  534.     xprintf("%s", prm); flush();
  535.     for (i = 0;;)  {
  536.     if (read(fd, &pass[i], 1) < 1 || pass[i] == '\n') 
  537.         break;
  538.     if (i < 8)
  539.         i++;
  540.     }
  541.     
  542.     pass[i] = '\0';
  543.  
  544.     if (fd != SHIN)
  545.     (void) close(fd);
  546.     (void) sigset(SIGINT, sigint);
  547.  
  548.     return(pass);
  549. }
  550.     
  551. /*
  552.  * Ask the user for his login password to continue working
  553.  * On systems that have a shadow password, this will only 
  554.  * work for root, but what can we do?
  555.  *
  556.  * If we fail to get the password, then we log the user out
  557.  * immediately
  558.  */
  559. static void
  560. auto_lock()
  561. {
  562. #ifndef NO_CRYPT
  563.  
  564.     int i;
  565.     char *srpp = NULL;
  566.     struct passwd *pw;
  567.  
  568. #undef XCRYPT
  569.  
  570. #if defined(PW_AUTH) && !defined(XCRYPT)
  571.  
  572.     struct authorization *apw;
  573.     extern char *crypt16();
  574.  
  575. # define XCRYPT(a, b) crypt16(a, b)
  576.  
  577.     if ((pw = getpwuid(euid)) != NULL &&    /* effective user passwd  */
  578.         (apw = getauthuid(euid)) != NULL)     /* enhanced ultrix passwd */
  579.     srpp = apw->a_password;
  580.  
  581. #endif /* PW_AUTH && !XCRYPT */
  582.  
  583. #if defined(PW_SHADOW) && !defined(XCRYPT)
  584.  
  585.     struct spwd *spw;
  586.     extern char *crypt();
  587.  
  588. # define XCRYPT(a, b) crypt(a, b)
  589.  
  590.     if ((pw = getpwuid(euid)) != NULL &&    /* effective user passwd  */
  591.     (spw = getspnam(pw->pw_name)) != NULL)    /* shadowed passwd      */
  592.     srpp = spw->sp_pwdp;
  593.  
  594. #endif /* PW_SHADOW && !XCRYPT */
  595.  
  596. #ifndef XCRYPT
  597.     extern char *crypt();
  598.  
  599. #define XCRYPT(a, b) crypt(a, b)
  600.  
  601.     if ((pw = getpwuid(euid)) != NULL)    /* effective user passwd  */
  602.     srpp = pw->pw_passwd;
  603.  
  604. #endif /* !XCRYPT */
  605.  
  606.     if (srpp == NULL) {
  607.     auto_logout();
  608.     /*NOTREACHED*/
  609.     return;
  610.     }
  611.  
  612.     setalarm(0);        /* Not for locking any more */
  613. #ifdef BSDSIGS
  614.     (void) sigsetmask(sigblock(0) & ~(sigmask(SIGALRM)));
  615. #else /* !BSDSIGS */
  616.     (void) sigrelse(SIGALRM);
  617. #endif /* BSDSIGS */
  618.     xputchar('\n'); 
  619.     for (i = 0; i < 5; i++) {
  620.     char *crpp, *pp;
  621.     pp = xgetpass("Password:"); 
  622.  
  623.     crpp = XCRYPT(pp, srpp);
  624.     if (strcmp(crpp, srpp) == 0) {
  625.         if (GettingInput && !just_signaled) {
  626.         (void) Rawmode();
  627.         ClearLines();    
  628.         ClearDisp();    
  629.         Refresh();
  630.         }
  631.         just_signaled = 0;
  632.         return;
  633.     }
  634.     xprintf("\nIncorrect passwd for %s\n", pw->pw_name);
  635.     }
  636. #endif /* NO_CRYPT */
  637.     auto_logout();
  638. }
  639.  
  640.  
  641. static void
  642. auto_logout()
  643. {
  644.     xprintf("auto-logout\n");
  645.     /* Don't leave the tty in raw mode */
  646.     if (editing)
  647.     (void) Cookedmode();
  648.     (void) close(SHIN);
  649.     set(STRlogout, Strsave(STRautomatic));
  650.     child = 1;
  651. #ifdef TESLA
  652.     do_logout = 1;
  653. #endif /* TESLA */
  654.     GettingInput = FALSE; /* make flush() work to write hist files. Huber*/
  655.     goodbye(NULL, NULL);
  656. }
  657.  
  658. sigret_t
  659. /*ARGSUSED*/
  660. alrmcatch(snum)
  661. int snum;
  662. {
  663. #ifdef UNRELSIGS
  664.     if (snum)
  665.     (void) sigset(SIGALRM, alrmcatch);
  666. #endif /* UNRELSIGS */
  667.  
  668.     (*alm_fun)();
  669.  
  670.     setalarm(1);
  671. #ifndef SIGVOID
  672.     return (snum);
  673. #endif /* !SIGVOID */
  674. }
  675.  
  676. /*
  677.  * Karl Kleinpaste, 21oct1983.
  678.  * Added precmd(), which checks for the alias
  679.  * precmd in aliases.  If it's there, the alias
  680.  * is executed as a command.  This is done
  681.  * after mailchk() and just before print-
  682.  * ing the prompt.  Useful for things like printing
  683.  * one's current directory just before each command.
  684.  */
  685. void
  686. precmd()
  687. {
  688. #ifdef BSDSIGS
  689.     sigmask_t omask;
  690.  
  691.     omask = sigblock(sigmask(SIGINT));
  692. #else /* !BSDSIGS */
  693.     (void) sighold(SIGINT);
  694. #endif /* BSDSIGS */
  695.     if (precmd_active) {    /* an error must have been caught */
  696.     aliasrun(2, STRunalias, STRprecmd);
  697.     xprintf("Faulty alias 'precmd' removed.\n");
  698.     goto leave;
  699.     }
  700.     precmd_active = 1;
  701.     if (!whyles && adrof1(STRprecmd, &aliases))
  702.     aliasrun(1, STRprecmd, NULL);
  703. leave:
  704.     precmd_active = 0;
  705. #ifdef BSDSIGS
  706.     (void) sigsetmask(omask);
  707. #else /* !BSDSIGS */
  708.     (void) sigrelse(SIGINT);
  709. #endif /* BSDSIGS */
  710. }
  711.  
  712. /*
  713.  * Paul Placeway  11/24/87  Added cwd_cmd by hacking precmd() into
  714.  * submission...  Run every time $cwd is set (after it is set).  Useful
  715.  * for putting your machine and cwd (or anything else) in an xterm title
  716.  * space.
  717.  */
  718. void
  719. cwd_cmd()
  720. {
  721. #ifdef BSDSIGS
  722.     sigmask_t omask;
  723.  
  724.     omask = sigblock(sigmask(SIGINT));
  725. #else /* !BSDSIGS */
  726.     (void) sighold(SIGINT);
  727. #endif /* BSDSIGS */
  728.     if (cwdcmd_active) {    /* an error must have been caught */
  729.     aliasrun(2, STRunalias, STRcwdcmd);
  730.     xprintf("Faulty alias 'cwdcmd' removed.\n");
  731.     goto leave;
  732.     }
  733.     cwdcmd_active = 1;
  734.     if (!whyles && adrof1(STRcwdcmd, &aliases))
  735.     aliasrun(1, STRcwdcmd, NULL);
  736. leave:
  737.     cwdcmd_active = 0;
  738. #ifdef BSDSIGS
  739.     (void) sigsetmask(omask);
  740. #else /* !BSDSIGS */
  741.     (void) sigrelse(SIGINT);
  742. #endif /* BSDSIGS */
  743. }
  744.  
  745. /*
  746.  * Joachim Hoenig  07/16/91  Added beep_cmd, run every time tcsh wishes 
  747.  * to beep the terminal bell. Useful for playing nice sounds instead.
  748.  */
  749. void
  750. beep_cmd()
  751. {
  752. #ifdef BSDSIGS
  753.     sigmask_t omask;
  754.  
  755.     omask = sigblock(sigmask(SIGINT));
  756. #else /* !BSDSIGS */
  757.     (void) sighold(SIGINT);
  758. #endif /* BSDSIGS */
  759.     if (beepcmd_active) {    /* an error must have been caught */
  760.     aliasrun(2, STRunalias, STRbeepcmd);
  761.     xprintf("Faulty alias 'beepcmd' removed.\n");
  762.     }
  763.     else {
  764.     beepcmd_active = 1;
  765.     if (!whyles && adrof1(STRbeepcmd, &aliases))
  766.         aliasrun(1, STRbeepcmd, NULL);
  767.     }
  768.     beepcmd_active = 0;
  769. #ifdef BSDSIGS
  770.     (void) sigsetmask(omask);
  771. #else /* !BSDSIGS */
  772.     (void) sigrelse(SIGINT);
  773. #endif /* BSDSIGS */
  774. }
  775.  
  776.  
  777. /*
  778.  * Karl Kleinpaste, 18 Jan 1984.
  779.  * Added period_cmd(), which executes the alias "periodic" every
  780.  * $tperiod minutes.  Useful for occasional checking of msgs and such.
  781.  */
  782. void
  783. period_cmd()
  784. {
  785.     register Char *vp;
  786.     time_t  t, interval;
  787. #ifdef BSDSIGS
  788.     sigmask_t omask;
  789.  
  790.     omask = sigblock(sigmask(SIGINT));
  791. #else /* !BSDSIGS */
  792.     (void) sighold(SIGINT);
  793. #endif /* BSDSIGS */
  794.     if (periodic_active) {    /* an error must have been caught */
  795.     aliasrun(2, STRunalias, STRperiodic);
  796.     xprintf("Faulty alias 'periodic' removed.\n");
  797.     goto leave;
  798.     }
  799.     periodic_active = 1;
  800.     if (!whyles && adrof1(STRperiodic, &aliases)) {
  801.     vp = value(STRtperiod);
  802.     if (vp == STRNULL)
  803.         return;
  804.     interval = getn(vp);
  805.     (void) time(&t);
  806.     if (t - t_period >= interval * 60) {
  807.         t_period = t;
  808.         aliasrun(1, STRperiodic, NULL);
  809.     }
  810.     }
  811. leave:
  812.     periodic_active = 0;
  813. #ifdef BSDSIGS
  814.     (void) sigsetmask(omask);
  815. #else /* !BSDSIGS */
  816.     (void) sigrelse(SIGINT);
  817. #endif /* BSDSIGS */
  818. }
  819.  
  820. /*
  821.  * Karl Kleinpaste, 21oct1983.
  822.  * Set up a one-word alias command, for use for special things.
  823.  * This code is based on the mainline of process().
  824.  */
  825. void
  826. aliasrun(cnt, s1, s2)
  827.     int     cnt;
  828.     Char   *s1, *s2;
  829. {
  830.     struct wordent w, *new1, *new2;    /* for holding alias name */
  831.     struct command *t = NULL;
  832.     jmp_buf_t osetexit;
  833.  
  834.     getexit(osetexit);
  835.     if (seterr) {
  836.     xfree((ptr_t) seterr);
  837.     seterr = NULL;    /* don't repeatedly print err msg. */
  838.     }
  839.     w.word = STRNULL;
  840.     new1 = (struct wordent *) xcalloc(1, sizeof w);
  841.     new1->word = Strsave(s1);
  842.     if (cnt == 1) {
  843.     /* build a lex list with one word. */
  844.     w.next = w.prev = new1;
  845.     new1->next = new1->prev = &w;
  846.     }
  847.     else {
  848.     /* build a lex list with two words. */
  849.     new2 = (struct wordent *) xcalloc(1, sizeof w);
  850.     new2->word = Strsave(s2);
  851.     w.next = new2->prev = new1;
  852.     new1->next = w.prev = new2;
  853.     new1->prev = new2->next = &w;
  854.     }
  855.  
  856.     /* expand aliases like process() does. */
  857.     alias(&w);
  858.     /* build a syntax tree for the command. */
  859.     t = syntax(w.next, &w, 0);
  860.     if (seterr)
  861.     stderror(ERR_OLD);
  862.  
  863.     psavejob();
  864.     /* catch any errors here */
  865.     if (setexit() == 0)
  866.     /* execute the parse tree. */
  867.     /*
  868.      * From: Michael Schroeder <mlschroe@immd4.informatik.uni-erlangen.de>
  869.      * was execute(t, tpgrp);
  870.      */
  871.     execute(t, tpgrp > 0 ? tpgrp : -1, NULL, NULL);    
  872.     /* done. free the lex list and parse tree. */
  873.     freelex(&w), freesyn(t);
  874.     if (haderr) {
  875.     haderr = 0;
  876.     /*
  877.      * Either precmd, or cwdcmd, or periodic had an error. Call it again so
  878.      * that it is removed
  879.      */
  880.     if (precmd_active)
  881.         precmd();
  882. #ifdef notdef
  883.     /*
  884.      * XXX: On the other hand, just interrupting them causes an error too.
  885.      * So if we hit ^C in the middle of cwdcmd or periodic the alias gets
  886.      * removed. We don't want that. Note that we want to remove precmd
  887.      * though, cause that could lead into an infinite loop. This should be
  888.      * fixed correctly, but then haderr should give us the whole exit
  889.      * status not just true or false.
  890.      */
  891.     else if (cwdcmd_active)
  892.         cwd_cmd();
  893.     else if (beepcmd_active)
  894.         beep_cmd();
  895.     else if (periodic_active)
  896.         period_cmd();
  897. #endif /* notdef */
  898.     }
  899.     /* reset the error catcher to the old place */
  900.     resexit(osetexit);
  901.     prestjob();
  902.     pendjob();
  903. }
  904.  
  905. void
  906. setalarm(lck)
  907.     int lck;
  908. {
  909.     struct varent *vp;
  910.     Char   *cp;
  911.     unsigned alrm_time = 0, logout_time, lock_time;
  912.     time_t cl, nl, sched_dif;
  913.  
  914.     if ((vp = adrof(STRautologout)) != NULL) {
  915.     if ((cp = vp->vec[0]) != 0) {
  916.         if ((logout_time = atoi(short2str(cp)) * 60) > 0) {
  917.         alrm_time = logout_time;
  918.         alm_fun = auto_logout;
  919.         }
  920.     }
  921.     if ((cp = vp->vec[1]) != 0) {
  922.         if ((lock_time = atoi(short2str(cp)) * 60) > 0) {
  923.         if (lck) {
  924.             if (alrm_time == 0 || lock_time < alrm_time) {
  925.             alrm_time = lock_time;
  926.             alm_fun = auto_lock;
  927.             }
  928.         }
  929.         else /* lock_time always < alrm_time */
  930.             if (alrm_time)
  931.             alrm_time -= lock_time;
  932.         }
  933.     }
  934.     }
  935.     if ((nl = sched_next()) != -1) {
  936.     (void) time(&cl);
  937.     sched_dif = nl > cl ? nl - cl : 0;
  938.     if ((alrm_time == 0) || ((unsigned) sched_dif < alrm_time)) {
  939.         alrm_time = ((unsigned) sched_dif) + 1;
  940.         alm_fun = sched_run;
  941.     }
  942.     }
  943.     (void) alarm(alrm_time);    /* Autologout ON */
  944. }
  945.  
  946. #undef RMDEBUG            /* For now... */
  947.  
  948. void
  949. rmstar(cp)
  950.     struct wordent *cp;
  951. {
  952.     struct wordent *we, *args;
  953.     register struct wordent *tmp, *del;
  954.  
  955. #ifdef RMDEBUG
  956.     static Char STRrmdebug[] = {'r', 'm', 'd', 'e', 'b', 'u', 'g', '\0'};
  957.     Char   *tag;
  958. #endif /* RMDEBUG */
  959.     Char   *charac;
  960.     char    c;
  961.     int     ask, doit, star = 0, silent = 0;
  962.  
  963.     if (!adrof(STRrmstar))
  964.     return;
  965. #ifdef RMDEBUG
  966.     tag = value(STRrmdebug);
  967. #endif /* RMDEBUG */
  968.     we = cp->next;
  969.     while (*we->word == ';' && we != cp)
  970.     we = we->next;
  971.     while (we != cp) {
  972. #ifdef RMDEBUG
  973.     if (*tag)
  974.         xprintf("parsing command line\n");
  975. #endif /* RMDEBUG */
  976.     if (!Strcmp(we->word, STRrm)) {
  977.         args = we->next;
  978.         ask = (*args->word != '-');
  979.         while (*args->word == '-' && !silent) {    /* check options */
  980.         for (charac = (args->word + 1); *charac && !silent; charac++)
  981.             silent = (*charac == 'i' || *charac == 'f');
  982.         args = args->next;
  983.         }
  984.         ask = (ask || (!ask && !silent));
  985.         if (ask) {
  986.         for (; !star && *args->word != ';'
  987.              && args != cp; args = args->next)
  988.             if (!Strcmp(args->word, STRstar))
  989.             star = 1;
  990.         if (ask && star) {
  991.             xprintf("Do you really want to delete all files? [n/y] ");
  992.             flush();
  993.             (void) read(SHIN, &c, 1);
  994.             doit = (c == 'Y' || c == 'y');
  995.             while (c != '\n')
  996.             (void) read(SHIN, &c, 1);
  997.             if (!doit) {
  998.             /* remove the command instead */
  999. #ifdef RMDEBUG
  1000.             if (*tag)
  1001.                 xprintf("skipping deletion of files!\n");
  1002. #endif /* RMDEBUG */
  1003.             for (tmp = we;
  1004.                  *tmp->word != '\n' &&
  1005.                  *tmp->word != ';' && tmp != cp;) {
  1006.                 tmp->prev->next = tmp->next;
  1007.                 tmp->next->prev = tmp->prev;
  1008.                 xfree((ptr_t) tmp->word);
  1009.                 del = tmp;
  1010.                 tmp = tmp->next;
  1011.                 xfree((ptr_t) del);
  1012.             }
  1013.             if (*tmp->word == ';') {
  1014.                 tmp->prev->next = tmp->next;
  1015.                 tmp->next->prev = tmp->prev;
  1016.                 xfree((ptr_t) tmp->word);
  1017.                 del = tmp;
  1018.                 xfree((ptr_t) del);
  1019.             }
  1020.             }
  1021.         }
  1022.         }
  1023.     }
  1024.     for (we = we->next;
  1025.          *we->word != ';' && we != cp;
  1026.          we = we->next)
  1027.         continue;
  1028.     if (*we->word == ';')
  1029.         we = we->next;
  1030.     }
  1031. #ifdef RMDEBUG
  1032.     if (*tag) {
  1033.     xprintf("command line now is:\n");
  1034.     for (we = cp->next; we != cp; we = we->next)
  1035.         xprintf("%S ", we->word);
  1036.     }
  1037. #endif /* RMDEBUG */
  1038.     return;
  1039. }
  1040.  
  1041. #ifdef BSDJOBS
  1042. /* Check if command is in continue list
  1043.    and do a "aliasing" if it exists as a job in background */
  1044.  
  1045. #undef CNDEBUG            /* For now */
  1046. void
  1047. continue_jobs(cp)
  1048.     struct wordent *cp;
  1049. {
  1050.     struct wordent *we;
  1051.     register struct process *pp, *np;
  1052.     Char   *cmd, *continue_list, *continue_args_list;
  1053.  
  1054. #ifdef CNDEBUG
  1055.     Char   *tag;
  1056.     static Char STRcndebug[] =
  1057.     {'c', 'n', 'd', 'e', 'b', 'u', 'g', '\0'};
  1058. #endif /* CNDEBUG */
  1059.     bool    in_cont_list, in_cont_arg_list;
  1060.  
  1061.  
  1062. #ifdef CNDEBUG
  1063.     tag = value(STRcndebug);
  1064. #endif /* CNDEBUG */
  1065.     continue_list = value(STRcontinue);
  1066.     continue_args_list = value(STRcontinue_args);
  1067.     if (*continue_list == '\0' && *continue_args_list == '\0')
  1068.     return;
  1069.  
  1070.     we = cp->next;
  1071.     while (*we->word == ';' && we != cp)
  1072.     we = we->next;
  1073.     while (we != cp) {
  1074. #ifdef CNDEBUG
  1075.     if (*tag)
  1076.         xprintf("parsing command line\n");
  1077. #endif /* CNDEBUG */
  1078.     cmd = we->word;
  1079.     in_cont_list = inlist(continue_list, cmd);
  1080.     in_cont_arg_list = inlist(continue_args_list, cmd);
  1081.     if (in_cont_list || in_cont_arg_list) {
  1082. #ifdef CNDEBUG
  1083.         if (*tag)
  1084.         xprintf("in one of the lists\n");
  1085. #endif /* CNDEBUG */
  1086.         np = NULL;
  1087.         for (pp = proclist.p_next; pp; pp = pp->p_next) {
  1088.         if (prefix(cmd, pp->p_command)) {
  1089.             if (pp->p_index) {
  1090.             np = pp;
  1091.             break;
  1092.             }
  1093.         }
  1094.         }
  1095.         if (np) {
  1096.         insert(we, in_cont_arg_list);
  1097.         }
  1098.     }
  1099.     for (we = we->next;
  1100.          *we->word != ';' && we != cp;
  1101.          we = we->next)
  1102.         continue;
  1103.     if (*we->word == ';')
  1104.         we = we->next;
  1105.     }
  1106. #ifdef CNDEBUG
  1107.     if (*tag) {
  1108.     xprintf("command line now is:\n");
  1109.     for (we = cp->next; we != cp; we = we->next)
  1110.         xprintf("%S ", we->word);
  1111.     }
  1112. #endif /* CNDEBUG */
  1113.     return;
  1114. }
  1115.  
  1116. /* The actual "aliasing" of for backgrounds() is done here
  1117.    with the aid of insert_we().   */
  1118. static void
  1119. insert(plist, file_args)
  1120.     struct wordent *plist;
  1121.     bool    file_args;
  1122. {
  1123.     struct wordent *now, *last;
  1124.     Char   *cmd, *bcmd, *cp1, *cp2;
  1125.     int     cmd_len;
  1126.     Char   *pause = STRunderpause;
  1127.     int     p_len = Strlen(pause);
  1128.  
  1129.     cmd_len = Strlen(plist->word);
  1130.     cmd = (Char *) xcalloc(1, (size_t) ((cmd_len + 1) * sizeof(Char)));
  1131.     (void) Strcpy(cmd, plist->word);
  1132. /* Do insertions at beginning, first replace command word */
  1133.  
  1134.     if (file_args) {
  1135.     now = plist;
  1136.     xfree((ptr_t) now->word);
  1137.     now->word = (Char *) xcalloc(1, (size_t) (5 * sizeof(Char)));
  1138.     (void) Strcpy(now->word, STRecho);
  1139.  
  1140.     now = (struct wordent *) xcalloc(1, (size_t) sizeof(struct wordent));
  1141.     now->word = (Char *) xcalloc(1, (size_t) (6 * sizeof(Char)));
  1142.     (void) Strcpy(now->word, STRbackqpwd);
  1143.     insert_we(now, plist);
  1144.  
  1145.     for (last = now; *last->word != '\n' && *last->word != ';';
  1146.          last = last->next)
  1147.         continue;
  1148.  
  1149.     now = (struct wordent *) xcalloc(1, (size_t) sizeof(struct wordent));
  1150.     now->word = (Char *) xcalloc(1, (size_t) (2 * sizeof(Char)));
  1151.     (void) Strcpy(now->word, STRgt);
  1152.     insert_we(now, last->prev);
  1153.  
  1154.     now = (struct wordent *) xcalloc(1, (size_t) sizeof(struct wordent));
  1155.     now->word = (Char *) xcalloc(1, (size_t) (2 * sizeof(Char)));
  1156.     (void) Strcpy(now->word, STRbang);
  1157.     insert_we(now, last->prev);
  1158.  
  1159.     now = (struct wordent *) xcalloc(1, (size_t) sizeof(struct wordent));
  1160.     now->word = (Char *) xcalloc(1, (size_t) cmd_len + p_len + 4);
  1161.     cp1 = now->word;
  1162.     cp2 = cmd;
  1163.     *cp1++ = '~';
  1164.     *cp1++ = '/';
  1165.     *cp1++ = '.';
  1166.     while ((*cp1++ = *cp2++) != '\0')
  1167.         continue;
  1168.     cp1--;
  1169.     cp2 = pause;
  1170.     while ((*cp1++ = *cp2++) != '\0')
  1171.         continue;
  1172.     insert_we(now, last->prev);
  1173.  
  1174.     now = (struct wordent *) xcalloc(1, (size_t) sizeof(struct wordent));
  1175.     now->word = (Char *) xcalloc(1, (size_t) (2 * sizeof(Char)));
  1176.     (void) Strcpy(now->word, STRsemi);
  1177.     insert_we(now, last->prev);
  1178.     bcmd = (Char *) xcalloc(1, (size_t) ((cmd_len + 2) * sizeof(Char)));
  1179.     cp1 = bcmd;
  1180.     cp2 = cmd;
  1181.     *cp1++ = '%';
  1182.     while ((*cp1++ = *cp2++) != '\0')
  1183.         continue;
  1184.     now = (struct wordent *) xcalloc(1, (size_t) (sizeof(struct wordent)));
  1185.     now->word = bcmd;
  1186.     insert_we(now, last->prev);
  1187.     }
  1188.     else {
  1189.     struct wordent *del;
  1190.  
  1191.     now = plist;
  1192.     xfree((ptr_t) now->word);
  1193.     now->word = (Char *) xcalloc(1, 
  1194.                      (size_t) ((cmd_len + 2) * sizeof(Char)));
  1195.     cp1 = now->word;
  1196.     cp2 = cmd;
  1197.     *cp1++ = '%';
  1198.     while ((*cp1++ = *cp2++) != '\0')
  1199.         continue;
  1200.     for (now = now->next;
  1201.          *now->word != '\n' && *now->word != ';' && now != plist;) {
  1202.         now->prev->next = now->next;
  1203.         now->next->prev = now->prev;
  1204.         xfree((ptr_t) now->word);
  1205.         del = now;
  1206.         now = now->next;
  1207.         xfree((ptr_t) del);
  1208.     }
  1209.     }
  1210. }
  1211.  
  1212. static void
  1213. insert_we(new, where)
  1214.     struct wordent *new, *where;
  1215. {
  1216.  
  1217.     new->prev = where;
  1218.     new->next = where->next;
  1219.     where->next = new;
  1220.     new->next->prev = new;
  1221. }
  1222.  
  1223. static int
  1224. inlist(list, name)
  1225.     Char   *list, *name;
  1226. {
  1227.     register Char *l, *n;
  1228.  
  1229.     l = list;
  1230.     n = name;
  1231.  
  1232.     while (*l && *n) {
  1233.     if (*l == *n) {
  1234.         l++;
  1235.         n++;
  1236.         if (*n == '\0' && (*l == ' ' || *l == '\0'))
  1237.         return (1);
  1238.         else
  1239.         continue;
  1240.     }
  1241.     else {
  1242.         while (*l && *l != ' ')
  1243.         l++;        /* skip to blank */
  1244.         while (*l && *l == ' ')
  1245.         l++;        /* and find first nonblank character */
  1246.         n = name;
  1247.     }
  1248.     }
  1249.     return (0);
  1250. }
  1251.  
  1252. #endif /* BSDJOBS */
  1253.  
  1254.  
  1255. /*
  1256.  * Implement a small cache for tilde names. This is used primarily
  1257.  * to expand tilde names to directories, but also
  1258.  * we can find users from their home directories for the tilde
  1259.  * prompt, on machines where yp lookup is slow this can be a big win...
  1260.  * As with any cache this can run out of sync, rehash can sync it again.
  1261.  */
  1262. static struct tildecache {
  1263.     Char   *user;
  1264.     Char   *home;
  1265.     int     hlen;
  1266. }      *tcache = NULL;
  1267.  
  1268. #define TILINCR 10
  1269. int tlength = 0;
  1270. static int tsize = TILINCR;
  1271.  
  1272. static int
  1273. tildecompare(p1, p2)
  1274.     struct tildecache *p1, *p2;
  1275. {
  1276.     return Strcmp(p1->user, p2->user);
  1277. }
  1278.  
  1279. static Char *
  1280. gethomedir(us)
  1281.     Char   *us;
  1282. {
  1283.     register struct passwd *pp;
  1284. #ifdef HESIOD
  1285.     char **res, **res1, *cp;
  1286.     Char *rp;
  1287. #endif /* HESIOD */
  1288.     
  1289.     pp = getpwnam(short2str(us));
  1290. #ifdef YPBUGS
  1291.     fix_yp_bugs();
  1292. #endif /* YPBUGS */
  1293.     if (pp != NULL)
  1294.     return Strsave(str2short(pp->pw_dir));
  1295. #ifdef HESIOD
  1296.     res = hes_resolve(short2str(us), "filsys");
  1297.     rp = 0;
  1298.     if (res != 0) {
  1299.     extern char *strtok();
  1300.     if ((*res) != 0) {
  1301.         /*
  1302.          * Look at the first token to determine how to interpret
  1303.          * the rest of it.
  1304.          * Yes, strtok is evil (it's not thread-safe), but it's also
  1305.          * easy to use.
  1306.          */
  1307.         cp = strtok(*res, " ");
  1308.         if (strcmp(cp, "AFS") == 0) {
  1309.         /* next token is AFS pathname.. */
  1310.         cp = strtok(NULL, " ");
  1311.         if (cp != NULL)
  1312.             rp = Strsave(str2short(cp));
  1313.         } else if (strcmp(cp, "NFS") == 0) {
  1314.         cp = NULL;
  1315.         if ((strtok(NULL, " ")) && /* skip remote pathname */
  1316.             (strtok(NULL, " ")) && /* skip host */
  1317.             (strtok(NULL, " ")) && /* skip mode */
  1318.             (cp = strtok(NULL, " "))) {
  1319.             rp = Strsave(str2short(cp));
  1320.         }
  1321.         }
  1322.     }
  1323.     for (res1 = res; *res1; res1++)
  1324.         free(*res1);
  1325.     return rp;
  1326.     }
  1327. #endif /* HESIOD */
  1328.     return NULL;
  1329. }
  1330.  
  1331. Char   *
  1332. gettilde(us)
  1333.     Char   *us;
  1334. {
  1335.     struct tildecache *bp1, *bp2, *bp;
  1336.     Char *hd;
  1337.  
  1338.     if (tcache == NULL)
  1339.     tcache = (struct tildecache *) xmalloc((size_t) (TILINCR *
  1340.                           sizeof(struct tildecache)));
  1341.     /*
  1342.      * Binary search
  1343.      */
  1344.     for (bp1 = tcache, bp2 = tcache + tlength; bp1 < bp2;) {
  1345.     register int i;
  1346.  
  1347.     bp = bp1 + ((bp2 - bp1) >> 1);
  1348.     if ((i = *us - *bp->user) == 0 && (i = Strcmp(us, bp->user)) == 0)
  1349.         return (bp->home);
  1350.     if (i < 0)
  1351.         bp2 = bp;
  1352.     else
  1353.         bp1 = bp + 1;
  1354.     }
  1355.     /*
  1356.      * Not in the cache, try to get it from the passwd file
  1357.      */
  1358.     hd = gethomedir(us);
  1359.     if (hd == NULL)
  1360.     return NULL;
  1361.  
  1362.     /*
  1363.      * Update the cache
  1364.      */
  1365.     tcache[tlength].user = Strsave(us);
  1366.     tcache[tlength].home = hd;
  1367.     tcache[tlength++].hlen = Strlen(hd);
  1368.  
  1369.     qsort((ptr_t) tcache, (size_t) tlength, sizeof(struct tildecache),
  1370.       (int (*) __P((const void *, const void *))) tildecompare);
  1371.  
  1372.     if (tlength == tsize) {
  1373.     tsize += TILINCR;
  1374.     tcache = (struct tildecache *) xrealloc((ptr_t) tcache,
  1375.                         (size_t) (tsize *
  1376.                           sizeof(struct tildecache)));
  1377.     }
  1378.     return (hd);
  1379. }
  1380.  
  1381. /*
  1382.  * Return the username if the directory path passed contains a
  1383.  * user's home directory in the tilde cache, otherwise return NULL
  1384.  * hm points to the place where the path became different.
  1385.  * Special case: Our own home directory.
  1386.  * If we are passed a null pointer, then we flush the cache.
  1387.  */
  1388. Char   *
  1389. getusername(hm)
  1390.     Char  **hm;
  1391. {
  1392.     Char   *h, *p;
  1393.     int     i, j;
  1394.  
  1395.     if (hm == NULL) {
  1396.     for (i = 0; i < tlength; i++) {
  1397.         xfree((ptr_t) tcache[i].home);
  1398.         xfree((ptr_t) tcache[i].user);
  1399.     }
  1400.     xfree((ptr_t) tcache);
  1401.     tlength = 0;
  1402.     tsize = TILINCR;
  1403.     tcache = NULL;
  1404.     return NULL;
  1405.     }
  1406.     if (((h = value(STRhome)) != STRNULL) &&
  1407.     (Strncmp(p = *hm, h, j = Strlen(h)) == 0) &&
  1408.     (p[j] == '/' || p[j] == '\0')) {
  1409.     *hm = &p[j];
  1410.     return STRNULL;
  1411.     }
  1412.     for (i = 0; i < tlength; i++)
  1413.     if ((Strncmp(p = *hm, tcache[i].home, j = tcache[i].hlen) == 0) &&
  1414.         (p[j] == '/' || p[j] == '\0')) {
  1415.         *hm = &p[j];
  1416.         return tcache[i].user;
  1417.     }
  1418.     return NULL;
  1419. }
  1420.  
  1421. /*
  1422.  * PWP: read a bunch of aliases out of a file QUICKLY.  The format
  1423.  *  is almost the same as the result of saying "alias > FILE", except
  1424.  *  that saying "aliases > FILE" does not expand non-letters to printable
  1425.  *  sequences.
  1426.  */
  1427. /*ARGSUSED*/
  1428. void
  1429. doaliases(v, c)
  1430.     Char  **v;
  1431.     struct command *c;
  1432. {
  1433.     jmp_buf_t oldexit;
  1434.     Char  **vec, *lp;
  1435.     int     fd;
  1436.     Char    buf[BUFSIZE], line[BUFSIZE];
  1437.     char    tbuf[BUFSIZE + 1], *tmp;
  1438.     extern bool output_raw;    /* PWP: in sh.print.c */
  1439.  
  1440.     v++;
  1441.     if (*v == 0) {
  1442.     output_raw = 1;
  1443.     plist(&aliases);
  1444.     output_raw = 0;
  1445.     return;
  1446.     }
  1447.  
  1448.     gflag = 0, tglob(v);
  1449.     if (gflag) {
  1450.     v = globall(v);
  1451.     if (v == 0)
  1452.         stderror(ERR_NAME | ERR_NOMATCH);
  1453.     }
  1454.     else {
  1455.     v = gargv = saveblk(v);
  1456.     trim(v);
  1457.     }
  1458.  
  1459.     if ((fd = open(tmp = short2str(*v), O_RDONLY)) < 0)
  1460.     stderror(ERR_NAME | ERR_SYSTEM, tmp, strerror(errno));
  1461.  
  1462.     getexit(oldexit);
  1463.     if (setexit() == 0) {
  1464.     for (;;) {
  1465.         Char   *p = NULL;
  1466.         int     n = 0;
  1467.         lp = line;
  1468.         for (;;) {
  1469.         if (n <= 0) {
  1470.             int     i;
  1471.  
  1472.             if ((n = read(fd, tbuf, BUFSIZE)) <= 0)
  1473.             goto eof;
  1474.             for (i = 0; i < n; i++)
  1475.             buf[i] = tbuf[i];
  1476.             p = buf;
  1477.         }
  1478.         n--;
  1479.         if ((*lp++ = *p++) == '\n') {
  1480.             lp[-1] = '\0';
  1481.             break;
  1482.         }
  1483.         }
  1484.         for (lp = line; *lp; lp++) {
  1485.         if (isspc(*lp)) {
  1486.             *lp++ = '\0';
  1487.             while (isspc(*lp))
  1488.             lp++;
  1489.             vec = (Char **) xmalloc((size_t)
  1490.                         (2 * sizeof(Char **)));
  1491.             vec[0] = Strsave(lp);
  1492.             vec[1] = NULL;
  1493.             setq(strip(line), vec, &aliases);
  1494.             break;
  1495.         }
  1496.         }
  1497.     }
  1498.     }
  1499.  
  1500. eof:
  1501.     (void) close(fd);
  1502.     tw_cmd_free();
  1503.     if (gargv)
  1504.     blkfree(gargv), gargv = 0;
  1505.     resexit(oldexit);
  1506. }
  1507.  
  1508.  
  1509. /*
  1510.  * set the shell-level var to 1 or apply change to it.
  1511.  */
  1512. void
  1513. shlvl(val)
  1514.     int val;
  1515. {
  1516.     char *cp;
  1517.  
  1518.     if ((cp = getenv("SHLVL")) != NULL) {
  1519.  
  1520.     if (loginsh)
  1521.         val = 1;
  1522.     else
  1523.         val += atoi(cp);
  1524.  
  1525.     if (val <= 0) {
  1526.         unsetv(STRshlvl);
  1527.         Unsetenv(STRKSHLVL);
  1528.     }
  1529.     else {
  1530.         Char    buff[BUFSIZE];
  1531.  
  1532.         Itoa(val, buff);
  1533.         set(STRshlvl, Strsave(buff));
  1534.         tsetenv(STRKSHLVL, buff);
  1535.     }
  1536.     }
  1537.     else {
  1538.     set(STRshlvl, SAVE("1"));
  1539.     tsetenv(STRKSHLVL, str2short("1"));
  1540.     }
  1541. }
  1542.  
  1543.  
  1544. /* fixio():
  1545.  *    Try to recover from a read error
  1546.  */
  1547. int
  1548. fixio(fd, e)
  1549.     int fd, e;
  1550. {
  1551.     switch (e) {
  1552.     case -1:    /* Make sure that the code is reachable */
  1553.  
  1554. #ifdef EWOULDBLOCK
  1555.     case EWOULDBLOCK:
  1556. # define TRY_AGAIN
  1557. #endif /* EWOULDBLOCK */
  1558.  
  1559. #if defined(POSIX) && defined(EAGAIN)
  1560. # if !defined(EWOULDBLOCK) || EWOULDBLOCK != EAGAIN
  1561.     case EAGAIN:
  1562. #  define TRY_AGAIN
  1563. # endif /* !EWOULDBLOCK || EWOULDBLOCK != EAGAIN */
  1564. #endif /* POSIX && EAGAIN */
  1565.  
  1566.     e = 0;
  1567. #ifdef TRY_AGAIN
  1568. # if defined(F_SETFL) && defined(O_NDELAY)
  1569.     if ((e = fcntl(fd, F_GETFL, 0)) == -1)
  1570.         return -1;
  1571.  
  1572.     if (fcntl(fd, F_SETFL, e & ~O_NDELAY) == -1)
  1573.         return -1;
  1574.     else 
  1575.         e = 1;
  1576. # endif /* F_SETFL && O_NDELAY */
  1577.  
  1578. # ifdef FIONBIO
  1579.     e = 0;
  1580.     if (ioctl(fd, FIONBIO, (ioctl_t) &e) == -1)
  1581.         return -1;
  1582.     else
  1583.         e = 1;
  1584. # endif    /* FIONBIO */
  1585.  
  1586. #endif /* TRY_AGAIN */
  1587.     return e ? 0 : -1;
  1588.  
  1589.     case EINTR:
  1590.     return 0;
  1591.  
  1592.     default:
  1593.     return -1;
  1594.     }
  1595. }
  1596.  
  1597. /* collate():
  1598.  *    String collation
  1599.  */
  1600. int
  1601. collate(a, b)
  1602.     const Char *a;
  1603.     const Char *b;
  1604. {
  1605.     int rv;
  1606.     /* This actually strips the quote bit */
  1607.     char *sa = strsave(short2str(a));
  1608.     char *sb = strsave(short2str(b));
  1609.  
  1610. #if defined(NLS) && !defined(NOSTRCOLL)
  1611.     errno = 0;    /* strcoll sets errno, another brain-damage */
  1612.  
  1613.     rv = strcoll(sa, sb);
  1614.  
  1615.     if (errno != 0) {
  1616.     xfree((ptr_t) sa);
  1617.     xfree((ptr_t) sb);
  1618.     stderror(ERR_SYSTEM, "strcoll", strerror(errno));
  1619.     }
  1620. #else
  1621.     rv = strcmp(sa, sb);
  1622. #endif /* NLS && !NOSTRCOLL */
  1623.  
  1624.     xfree((ptr_t) sa);
  1625.     xfree((ptr_t) sb);
  1626.  
  1627.     return rv;
  1628. }
  1629.  
  1630. #ifdef HASHBANG
  1631. /*
  1632.  * From: peter@zeus.dialix.oz.au (Peter Wemm)
  1633.  * If exec() fails look first for a #! [word] [word] ....
  1634.  * If it is, splice the header into the argument list and retry.
  1635.  */
  1636. #define HACKBUFSZ 1024        /* Max chars in #! vector */
  1637. #define HACKVECSZ 128        /* Max words in #! vector */
  1638. int
  1639. hashbang(fd, vp)
  1640.     int fd;
  1641.     Char ***vp;
  1642. {
  1643.     unsigned char lbuf[HACKBUFSZ];
  1644.     char *sargv[HACKVECSZ];
  1645.     unsigned char *p, *ws;
  1646.     int sargc = 0;
  1647.  
  1648.     if (read(fd, (char *) lbuf, HACKBUFSZ) <= 0)
  1649.     return -1;
  1650.  
  1651.     ws = 0;    /* word started = 0 */
  1652.  
  1653.     for (p = lbuf; p < &lbuf[HACKBUFSZ]; )
  1654.     switch (*p) {
  1655.     case ' ':
  1656.     case '\t':
  1657.         if (ws) {    /* a blank after a word.. save it */
  1658.         *p = '\0';
  1659.         if (sargc < HACKVECSZ - 1)
  1660.             sargv[sargc++] = ws;
  1661.         ws = NULL;
  1662.         }
  1663.         p++;
  1664.         continue;
  1665.  
  1666.     case '\0':    /* Whoa!! what the hell happened */
  1667.         return -1;
  1668.  
  1669.     case '\n':    /* The end of the line. */
  1670.         if (ws) {    /* terminate the last word */
  1671.         *p = '\0';
  1672.         if (sargc < HACKVECSZ - 1)
  1673.             sargv[sargc++] = ws;
  1674.         sargv[sargc] = NULL;
  1675.         ws = NULL;
  1676.         *vp = blk2short(sargv);
  1677.         return 0;
  1678.         }
  1679.         else
  1680.         return -1;
  1681.  
  1682.     default:
  1683.         if (!ws)    /* Start a new word? */
  1684.         ws = p; 
  1685.         p++;
  1686.         break;
  1687.     }
  1688.     return -1;
  1689. }
  1690. #endif /* HASHBANG */
  1691.