source: trunk/third/tcsh/sh.hist.c @ 22051

Revision 22051, 11.1 KB checked in by ghudson, 20 years ago (diff)
Fix to previous commit: don't log when reading history file.
Line 
1/* $Header: /afs/dev.mit.edu/source/repository/third/tcsh/sh.hist.c,v 1.4 2005-06-09 15:35:32 ghudson Exp $ */
2/*
3 * sh.hist.c: Shell history expansions and substitutions
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. Neither the name of the University nor the names of its contributors
18 *    may be used to endorse or promote products derived from this software
19 *    without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33#include "sh.h"
34
35RCSID("$Id: sh.hist.c,v 1.4 2005-06-09 15:35:32 ghudson Exp $")
36
37#include "tc.h"
38
39extern int histvalid;
40extern Char histline[];
41Char HistLit = 0;
42
43static  int     heq     __P((struct wordent *, struct wordent *));
44static  void    hfree   __P((struct Hist *));
45static  void    dohist1 __P((struct Hist *, int *, int));
46static  void    phist   __P((struct Hist *, int));
47
48#define HIST_ONLY       0x01
49#define HIST_SAVE       0x02
50#define HIST_LOAD       0x04
51#define HIST_REV        0x08
52#define HIST_CLEAR      0x10
53#define HIST_MERGE      0x20
54#define HIST_TIME       0x40
55
56/*
57 * C shell
58 */
59
60#include <syslog.h>
61
62void
63savehist(sp, mflg)
64    struct wordent *sp;
65    int mflg;
66{
67    struct Hist *hp, *np;
68    int histlen = 0;
69    Char   *cp;
70    char buf[INBUFSIZE];
71    static int do_log = -1;
72
73    /* throw away null lines */
74    if (sp && sp->next->word[0] == '\n')
75        return;
76    cp = varval(STRhistory);
77    if (*cp) {
78        Char *p = cp;
79
80        while (*p) {
81            if (!Isdigit(*p)) {
82                histlen = 0;
83                break;
84            }
85            histlen = histlen * 10 + *p++ - '0';
86        }
87    }
88    if (sp) {
89        extern int enterhist;
90        hp = enthist(++eventno, sp, 1, mflg);
91        if (do_log == -1) {
92            do_log = (geteuid() == 0
93                      && access("/var/athena/iscluster", R_OK) == 0);
94        }
95        if (do_log && !enterhist) {
96            fmthist('R', hp, buf, INBUFSIZE);
97            syslog(LOG_NOTICE, "Cluster root command (%d): %s",
98                   (int) getuid(), buf);
99        }
100    }
101    for (hp = &Histlist; (np = hp->Hnext) != NULL;)
102        if (eventno - np->Href >= histlen || histlen == 0)
103            hp->Hnext = np->Hnext, hfree(np);
104        else
105            hp = np;
106}
107
108static int
109heq(a0, b0)
110    struct wordent *a0, *b0;
111{
112    struct wordent *a = a0->next, *b = b0->next;
113
114    for (;;) {
115        if (Strcmp(a->word, b->word) != 0)
116            return 0;
117        a = a->next;
118        b = b->next;
119        if (a == a0)
120            return (b == b0) ? 1 : 0;
121        if (b == b0)
122            return 0;
123    }
124}
125
126
127struct Hist *
128enthist(event, lp, docopy, mflg)
129    int     event;
130    struct wordent *lp;
131    int    docopy;
132    int    mflg;
133{
134    struct Hist *p = NULL, *pp = &Histlist;
135    int n, r;
136    struct Hist *np;
137    Char *dp;
138   
139    if ((dp = varval(STRhistdup)) != STRNULL) {
140        if (eq(dp, STRerase)) {
141            /* masaoki@akebono.tky.hp.com (Kobayashi Masaoki) */
142            struct Hist *px;
143            for (p = pp; (px = p, p = p->Hnext) != NULL;)
144                if (heq(lp, &(p->Hlex))){
145                    px->Hnext = p->Hnext;
146                    if (Htime != 0 && p->Htime > Htime)
147                        Htime = p->Htime;
148                    n = p->Href;
149                    hfree(p);
150                    for (p = px->Hnext; p != NULL; p = p->Hnext)
151                        p->Href = n--;
152                    break;
153                }
154        }
155        else if (eq(dp, STRall)) {
156            for (p = pp; (p = p->Hnext) != NULL;)
157                if (heq(lp, &(p->Hlex))) {
158                    eventno--;
159                    break;
160                }
161        }
162        else if (eq(dp, STRprev)) {
163            if (pp->Hnext && heq(lp, &(pp->Hnext->Hlex))) {
164                p = pp->Hnext;
165                eventno--;
166            }
167        }
168    }
169
170    np = p ? p : (struct Hist *) xmalloc((size_t) sizeof(*np));
171
172    /* Pick up timestamp set by lex() in Htime if reading saved history */
173    if (Htime != (time_t) 0) {
174        np->Htime = Htime;
175        Htime = 0;
176    }
177    else
178        (void) time(&(np->Htime));
179
180    if (p == np)
181        return np;
182
183    np->Hnum = np->Href = event;
184    if (docopy) {
185        copylex(&np->Hlex, lp);
186        if (histvalid)
187            np->histline = Strsave(histline);
188        else
189            np->histline = NULL;
190    }
191    else {
192        np->Hlex.next = lp->next;
193        lp->next->prev = &np->Hlex;
194        np->Hlex.prev = lp->prev;
195        lp->prev->next = &np->Hlex;
196        np->histline = NULL;
197    }
198    if (mflg)
199      {
200        while ((p = pp->Hnext) && (p->Htime > np->Htime))
201          pp = p;
202        while (p && p->Htime == np->Htime)
203          {
204            if (heq(&p->Hlex, &np->Hlex))
205              {
206                eventno--;
207                hfree(np);
208                return (p);
209              }
210            pp = p;
211            p = p->Hnext;
212          }
213        for (p = Histlist.Hnext; p != pp->Hnext; p = p->Hnext)
214          {
215            n = p->Hnum; r = p->Href;
216            p->Hnum = np->Hnum; p->Href = np->Href;
217            np->Hnum = n; np->Href = r;
218          }
219      }
220    np->Hnext = pp->Hnext;
221    pp->Hnext = np;
222    return (np);
223}
224
225static void
226hfree(hp)
227    struct Hist *hp;
228{
229
230    freelex(&hp->Hlex);
231    if (hp->histline)
232        xfree((ptr_t) hp->histline);
233    xfree((ptr_t) hp);
234}
235
236
237/*ARGSUSED*/
238void
239dohist(vp, c)
240    Char  **vp;
241    struct command *c;
242{
243    int     n, hflg = 0;
244
245    USE(c);
246    if (getn(varval(STRhistory)) == 0)
247        return;
248    if (setintr)
249#ifdef BSDSIGS
250        (void) sigsetmask(sigblock((sigmask_t) 0) & ~sigmask(SIGINT));
251#else
252        (void) sigrelse(SIGINT);
253#endif
254    while (*++vp && **vp == '-') {
255        Char   *vp2 = *vp;
256
257        while (*++vp2)
258            switch (*vp2) {
259            case 'c':
260                hflg |= HIST_CLEAR;
261                break;
262            case 'h':
263                hflg |= HIST_ONLY;
264                break;
265            case 'r':
266                hflg |= HIST_REV;
267                break;
268            case 'S':
269                hflg |= HIST_SAVE;
270                break;
271            case 'L':
272                hflg |= HIST_LOAD;
273                break;
274            case 'M':
275                hflg |= HIST_MERGE;
276                break;
277            case 'T':
278                hflg |= HIST_TIME;
279                break;
280            default:
281                stderror(ERR_HISTUS, "chrSLMT");
282                break;
283            }
284    }
285
286    if (hflg & HIST_CLEAR) {
287        struct Hist *np, *hp;
288        for (hp = &Histlist; (np = hp->Hnext) != NULL;)
289            hp->Hnext = np->Hnext, hfree(np);
290    }
291
292    if (hflg & (HIST_LOAD | HIST_MERGE)) {
293        loadhist(*vp, (hflg & HIST_MERGE) ? 1 : 0);
294        return;
295    }
296    else if (hflg & HIST_SAVE) {
297        rechist(*vp, 1);
298        return;
299    }
300    if (*vp)
301        n = getn(*vp);
302    else {
303        n = getn(varval(STRhistory));
304    }
305    dohist1(Histlist.Hnext, &n, hflg);
306}
307
308static void
309dohist1(hp, np, hflg)
310    struct Hist *hp;
311    int    *np, hflg;
312{
313    int    print = (*np) > 0;
314
315    for (; hp != 0; hp = hp->Hnext) {
316        (*np)--;
317        if ((hflg & HIST_REV) == 0) {
318            dohist1(hp->Hnext, np, hflg);
319            if (print)
320                phist(hp, hflg);
321            return;
322        }
323        if (*np >= 0)
324            phist(hp, hflg);
325    }
326}
327
328static void
329phist(hp, hflg)
330    struct Hist *hp;
331    int     hflg;
332{
333    if (hflg & HIST_ONLY) {
334       /*
335        * Control characters have to be written as is (output_raw).
336        * This way one can preserve special characters (like tab) in
337        * the history file.
338        * From: mveksler@vnet.ibm.com (Veksler Michael)
339        */
340        output_raw= 1;
341        if (hflg & HIST_TIME)
342            /*
343             * Make file entry with history time in format:
344             * "+NNNNNNNNNN" (10 digits, left padded with ascii '0')
345             */
346
347            xprintf("#+%010lu\n", hp->Htime);
348
349        if (HistLit && hp->histline)
350            xprintf("%S\n", hp->histline);
351        else
352            prlex(&hp->Hlex);
353        output_raw= 0;
354    }
355    else {
356        Char   *cp = str2short("%h\t%T\t%R\n");
357        Char buf[INBUFSIZE];
358        struct varent *vp = adrof(STRhistory);
359
360        if (vp && vp->vec != NULL && vp->vec[0] && vp->vec[1])
361            cp = vp->vec[1];
362
363        tprintf(FMT_HISTORY, buf, cp, INBUFSIZE, NULL, hp->Htime, (ptr_t) hp);
364        for (cp = buf; *cp;)
365            xputwchar(*cp++);
366    }
367}
368
369
370void
371fmthist(fmt, ptr, buf, bufsiz)
372    int fmt;
373    ptr_t ptr;
374    char *buf;
375    size_t bufsiz;
376{
377    struct Hist *hp = (struct Hist *) ptr;
378    switch (fmt) {
379    case 'h':
380        (void) xsnprintf(buf, bufsiz, "%6d", hp->Hnum);
381        break;
382    case 'R':
383        if (HistLit && hp->histline)
384            (void) xsnprintf(buf, bufsiz, "%S", hp->histline);
385        else {
386            Char ibuf[INBUFSIZE], *ip;
387            char *p;
388            (void) sprlex(ibuf, sizeof(ibuf) / sizeof(Char), &hp->Hlex);
389            p = buf;
390            ip = ibuf;
391            do {
392                char xbuf[MB_LEN_MAX];
393                size_t len;
394
395                len = one_wctomb(xbuf, CHAR & *ip);
396                if ((size_t)((p - buf) + len) >= bufsiz)
397                    break;
398                memcpy(p, xbuf, len);
399                p += len;
400            } while ((CHAR & *ip++) != 0);
401            if (p <= buf + bufsiz - 1)
402                *p = '\0';
403        }
404        break;
405    default:
406        buf[0] = '\0';
407        break;
408    }
409       
410}
411
412void
413rechist(fname, ref)
414    Char *fname;
415    int ref;
416{
417    Char    *snum;
418    int     fp, ftmp, oldidfds;
419    struct varent *shist;
420    static Char   *dumphist[] = {STRhistory, STRmhT, 0, 0};
421
422    if (fname == NULL && !ref)
423        return;
424    /*
425     * If $savehist is just set, we use the value of $history
426     * else we use the value in $savehist
427     */
428    if (((snum = varval(STRsavehist)) == STRNULL) &&
429        ((snum = varval(STRhistory)) == STRNULL))
430        snum = STRmaxint;
431
432
433    if (fname == NULL) {
434        if ((fname = varval(STRhistfile)) == STRNULL)
435            fname = Strspl(varval(STRhome), &STRtildothist[1]);
436        else
437            fname = Strsave(fname);
438    }
439    else
440        fname = globone(fname, G_ERROR);
441
442    /*
443     * The 'savehist merge' feature is intended for an environment
444     * with numerous shells beeing in simultaneous use. Imagine
445     * any kind of window system. All these shells 'share' the same
446     * ~/.history file for recording their command line history.
447     * Currently the automatic merge can only succeed when the shells
448     * nicely quit one after another.
449     *
450     * Users that like to nuke their environment require here an atomic
451     *  loadhist-creat-dohist(dumphist)-close
452     * sequence.
453     *
454     * jw.
455     */
456    /*
457     * We need the didfds stuff before loadhist otherwise
458     * exec in a script will fail to print if merge is set.
459     * From: mveksler@iil.intel.com (Veksler Michael)
460     */
461    oldidfds = didfds;
462    didfds = 0;
463    if ((shist = adrof(STRsavehist)) != NULL && shist->vec != NULL)
464        if (shist->vec[1] && eq(shist->vec[1], STRmerge))
465            loadhist(fname, 1);
466    fp = creat(short2str(fname), 0600);
467    if (fp == -1) {
468        didfds = oldidfds;
469        return;
470    }
471    ftmp = SHOUT;
472    SHOUT = fp;
473    dumphist[2] = snum;
474    dohist(dumphist, NULL);
475    (void) close(fp);
476    SHOUT = ftmp;
477    didfds = oldidfds;
478    xfree((ptr_t) fname);
479}
480
481
482void
483loadhist(fname, mflg)
484    Char *fname;
485    int mflg;
486{
487    static Char   *loadhist_cmd[] = {STRsource, NULL, NULL, NULL};
488    loadhist_cmd[1] = mflg ? STRmm : STRmh;
489
490    if (fname != NULL)
491        loadhist_cmd[2] = fname;
492    else if ((fname = varval(STRhistfile)) != STRNULL)
493        loadhist_cmd[2] = fname;
494    else
495        loadhist_cmd[2] = STRtildothist;
496
497    dosource(loadhist_cmd, NULL);
498}
Note: See TracBrowser for help on using the repository browser.