source: trunk/third/tcsh/tc.func.c @ 9006

Revision 9006, 37.7 KB checked in by ghudson, 28 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r9005, which included commits to RCS files with non-trunk default branches.
Line 
1/* $Header: /afs/dev.mit.edu/source/repository/third/tcsh/tc.func.c,v 1.1.1.1 1996-10-02 06:09:28 ghudson 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
39RCSID("$Id: tc.func.c,v 1.1.1.1 1996-10-02 06:09:28 ghudson 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
50extern time_t t_period;
51extern int do_logout;
52extern int just_signaled;
53static bool precmd_active = 0;
54static bool periodic_active = 0;
55static bool cwdcmd_active = 0;  /* PWP: for cwd_cmd */
56static bool beepcmd_active = 0;
57static void (*alm_fun)() = NULL;
58
59static  void     Reverse        __P((Char *));
60static  void     auto_logout    __P((void));
61static  char    *xgetpass       __P((char *));
62static  void     auto_lock      __P((void));
63#ifdef BSDJOBS
64static  void     insert         __P((struct wordent *, bool));
65static  void     insert_we      __P((struct wordent *, struct wordent *));
66static  int      inlist         __P((Char *, Char *));
67#endif /* BSDJOBS */
68static  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
87Char   *
88expand_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
142Char   *
143sprlex(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
154void
155Itoa(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
173static void
174Reverse(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*/
188void
189dolist(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
329static char *defaulttell = "ALL";
330extern bool GotTermCaps;
331
332/*ARGSUSED*/
333void
334dotelltc(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*/
346void
347doechotc(v, c)
348    register Char **v;
349    struct command *c;
350{
351    if (!GotTermCaps)
352        GetTermCaps();
353    EchoTC(++v);
354}
355
356/*ARGSUSED*/
357void
358dosettc(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*/
382void
383dowhich(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
430struct process *
431find_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
479void
480fg_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
521static char *
522xgetpass(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 */
559static void
560auto_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
641static void
642auto_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
658sigret_t
659/*ARGSUSED*/
660alrmcatch(snum)
661int 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 */
685void
686precmd()
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);
703leave:
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 */
718void
719cwd_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);
736leave:
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 */
749void
750beep_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 */
782void
783period_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    }
811leave:
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 */
825void
826aliasrun(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
905void
906setalarm(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
948void
949rmstar(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 */
1046void
1047continue_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().   */
1118static void
1119insert(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
1212static void
1213insert_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
1223static int
1224inlist(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 */
1262static struct tildecache {
1263    Char   *user;
1264    Char   *home;
1265    int     hlen;
1266}      *tcache = NULL;
1267
1268#define TILINCR 10
1269int tlength = 0;
1270static int tsize = TILINCR;
1271
1272static int
1273tildecompare(p1, p2)
1274    struct tildecache *p1, *p2;
1275{
1276    return Strcmp(p1->user, p2->user);
1277}
1278
1279static Char *
1280gethomedir(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
1331Char   *
1332gettilde(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 */
1388Char   *
1389getusername(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*/
1428void
1429doaliases(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
1500eof:
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 */
1512void
1513shlvl(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 */
1547int
1548fixio(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 */
1600int
1601collate(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 */
1638int
1639hashbang(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 */
Note: See TracBrowser for help on using the repository browser.