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

Revision 12039, 10.8 KB checked in by danw, 26 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r12038, which included commits to RCS files with non-trunk default branches.
Line 
1/* $Header: /afs/dev.mit.edu/source/repository/third/tcsh/sh.hist.c,v 1.1.1.2 1998-10-03 21:10:02 danw 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. 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: sh.hist.c,v 1.1.1.2 1998-10-03 21:10:02 danw Exp $")
40
41#include "tc.h"
42
43extern bool histvalid;
44extern Char histline[];
45Char HistLit = 0;
46
47static  bool    heq     __P((struct wordent *, struct wordent *));
48static  void    hfree   __P((struct Hist *));
49static  void    dohist1 __P((struct Hist *, int *, int));
50static  void    phist   __P((struct Hist *, int));
51
52#define HIST_ONLY       0x01
53#define HIST_SAVE       0x02
54#define HIST_LOAD       0x04
55#define HIST_REV        0x08
56#define HIST_CLEAR      0x10
57#define HIST_MERGE      0x20
58#define HIST_TIME       0x40
59
60/*
61 * C shell
62 */
63
64void
65savehist(sp, mflg)
66    struct wordent *sp;
67    bool mflg;
68{
69    register struct Hist *hp, *np;
70    register int histlen = 0;
71    Char   *cp;
72
73    /* throw away null lines */
74    if (sp && sp->next->word[0] == '\n')
75        return;
76    cp = varval(STRhistory);
77    if (*cp) {
78        register 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    for (hp = &Histlist; (np = hp->Hnext) != NULL;)
89        if (eventno - np->Href >= histlen || histlen == 0)
90            hp->Hnext = np->Hnext, hfree(np);
91        else
92            hp = np;
93    if (sp)
94        (void) enthist(++eventno, sp, 1, mflg);
95}
96
97static bool
98heq(a0, b0)
99    struct wordent *a0, *b0;
100{
101    struct wordent *a = a0->next, *b = b0->next;
102
103    for (;;) {
104        if (Strcmp(a->word, b->word) != 0)
105            return 0;
106        a = a->next;
107        b = b->next;
108        if (a == a0)
109            return (b == b0) ? 1 : 0;
110        if (b == b0)
111            return 0;
112    }
113}
114
115
116struct Hist *
117enthist(event, lp, docopy, mflg)
118    int     event;
119    register struct wordent *lp;
120    bool    docopy;
121    bool    mflg;
122{
123    extern time_t Htime;
124    struct Hist *p = NULL, *pp = &Histlist;
125    int n, r;
126    register struct Hist *np;
127    Char *dp;
128   
129    if ((dp = varval(STRhistdup)) != STRNULL) {
130        if (eq(dp, STRerase)) {
131            /* masaoki@akebono.tky.hp.com (Kobayashi Masaoki) */
132            struct Hist *px;
133            for (p = pp; (px = p, p = p->Hnext) != NULL;)
134                if (heq(lp, &(p->Hlex))){
135                    px->Hnext = p->Hnext;
136                    n = p->Hnum + 1;
137                    hfree(p);
138                    for (p = px->Hnext; p != NULL; p = p->Hnext)
139                        p->Href = n--;
140                    break;
141                }
142        }
143        else if (eq(dp, STRall)) {
144            for (p = pp; (p = p->Hnext) != NULL;)
145                if (heq(lp, &(p->Hlex))) {
146                    eventno--;
147                    break;
148                }
149        }
150        else if (eq(dp, STRprev)) {
151            if (pp->Hnext && heq(lp, &(pp->Hnext->Hlex))) {
152                p = pp->Hnext;
153                eventno--;
154            }
155        }
156    }
157
158    np = p ? p : (struct Hist *) xmalloc((size_t) sizeof(*np));
159
160    /* Pick up timestamp set by lex() in Htime if reading saved history */
161    if (Htime != (time_t) 0) {
162        np->Htime = Htime;
163        Htime = 0;
164    }
165    else
166        (void) time(&(np->Htime));
167
168    if (p == np)
169        return np;
170
171    np->Hnum = np->Href = event;
172    if (docopy) {
173        copylex(&np->Hlex, lp);
174        if (histvalid)
175            np->histline = Strsave(histline);
176        else
177            np->histline = NULL;
178    }
179    else {
180        np->Hlex.next = lp->next;
181        lp->next->prev = &np->Hlex;
182        np->Hlex.prev = lp->prev;
183        lp->prev->next = &np->Hlex;
184        np->histline = NULL;
185    }
186    if (mflg)
187      {
188        while ((p = pp->Hnext) && (p->Htime > np->Htime))
189          pp = p;
190        while (p && p->Htime == np->Htime)
191          {
192            if (heq(&p->Hlex, &np->Hlex))
193              {
194                eventno--;
195                hfree(np);
196                return (p);
197              }
198            pp = p;
199            p = p->Hnext;
200          }
201        for (p = Histlist.Hnext; p != pp->Hnext; p = p->Hnext)
202          {
203            n = p->Hnum; r = p->Href;
204            p->Hnum = np->Hnum; p->Href = np->Href;
205            np->Hnum = n; np->Href = r;
206          }
207      }
208    np->Hnext = pp->Hnext;
209    pp->Hnext = np;
210    return (np);
211}
212
213static void
214hfree(hp)
215    register struct Hist *hp;
216{
217
218    freelex(&hp->Hlex);
219    if (hp->histline)
220        xfree((ptr_t) hp->histline);
221    xfree((ptr_t) hp);
222}
223
224
225/*ARGSUSED*/
226void
227dohist(vp, c)
228    Char  **vp;
229    struct command *c;
230{
231    int     n, hflg = 0;
232
233    USE(c);
234    if (getn(varval(STRhistory)) == 0)
235        return;
236    if (setintr)
237#ifdef BSDSIGS
238        (void) sigsetmask(sigblock((sigmask_t) 0) & ~sigmask(SIGINT));
239#else
240        (void) sigrelse(SIGINT);
241#endif
242    while (*++vp && **vp == '-') {
243        Char   *vp2 = *vp;
244
245        while (*++vp2)
246            switch (*vp2) {
247            case 'c':
248                hflg |= HIST_CLEAR;
249                break;
250            case 'h':
251                hflg |= HIST_ONLY;
252                break;
253            case 'r':
254                hflg |= HIST_REV;
255                break;
256            case 'S':
257                hflg |= HIST_SAVE;
258                break;
259            case 'L':
260                hflg |= HIST_LOAD;
261                break;
262            case 'M':
263                hflg |= HIST_MERGE;
264                break;
265            case 'T':
266                hflg |= HIST_TIME;
267                break;
268            default:
269                stderror(ERR_HISTUS, "chrSLMT");
270                break;
271            }
272    }
273
274    if (hflg & HIST_CLEAR) {
275        struct Hist *np, *hp;
276        for (hp = &Histlist; (np = hp->Hnext) != NULL;)
277            hp->Hnext = np->Hnext, hfree(np);
278    }
279
280    if (hflg & (HIST_LOAD | HIST_MERGE)) {
281        loadhist(*vp, (hflg & HIST_MERGE) ? 1 : 0);
282        return;
283    }
284    else if (hflg & HIST_SAVE) {
285        rechist(*vp, 1);
286        return;
287    }
288    if (*vp)
289        n = getn(*vp);
290    else {
291        n = getn(varval(STRhistory));
292    }
293    dohist1(Histlist.Hnext, &n, hflg);
294}
295
296static void
297dohist1(hp, np, hflg)
298    struct Hist *hp;
299    int    *np, hflg;
300{
301    bool    print = (*np) > 0;
302
303    for (; hp != 0; hp = hp->Hnext) {
304        (*np)--;
305        hp->Href++;
306        if ((hflg & HIST_REV) == 0) {
307            dohist1(hp->Hnext, np, hflg);
308            if (print)
309                phist(hp, hflg);
310            return;
311        }
312        if (*np >= 0)
313            phist(hp, hflg);
314    }
315}
316
317static void
318phist(hp, hflg)
319    register struct Hist *hp;
320    int     hflg;
321{
322    extern bool output_raw;
323    if (hflg & HIST_ONLY) {
324       /*
325        * Control characters have to be written as is (output_raw).
326        * This way one can preserve special characters (like tab) in
327        * the history file.
328        * From: mveksler@vnet.ibm.com (Veksler Michael)
329        */
330        output_raw= 1;
331        if (hflg & HIST_TIME)
332            /*
333             * Make file entry with history time in format:
334             * "+NNNNNNNNNN" (10 digits, left padded with ascii '0')
335             */
336
337            xprintf("#+%010lu\n", hp->Htime);
338
339        if (HistLit && hp->histline)
340            xprintf("%S\n", hp->histline);
341        else
342            prlex(&hp->Hlex);
343        output_raw= 0;
344    }
345    else {
346        Char   *cp = str2short("%h\t%T\t%R\n");
347        Char buf[INBUFSIZE];
348        struct varent *vp = adrof(STRhistory);
349
350        if (vp && vp->vec[0] && vp->vec[1])
351            cp = vp->vec[1];
352
353        tprintf(FMT_HISTORY, buf, cp, INBUFSIZE, NULL, hp->Htime, (ptr_t) hp);
354        for (cp = buf; *cp;)
355            xputchar(*cp++);
356    }
357}
358
359
360void
361fmthist(fmt, ptr, buf, bufsiz)
362    int fmt;
363    ptr_t ptr;
364    char *buf;
365    size_t bufsiz;
366{
367    struct Hist *hp = (struct Hist *) ptr;
368    switch (fmt) {
369    case 'h':
370        (void) xsnprintf(buf, bufsiz, "%6d", hp->Hnum);
371        break;
372    case 'R':
373        if (HistLit && hp->histline)
374            (void) xsnprintf(buf, bufsiz, "%S", hp->histline);
375        else {
376            Char ibuf[INBUFSIZE], *ip;
377            char *p;
378            (void) sprlex(ibuf, sizeof(ibuf), &hp->Hlex);
379            for (p = buf, ip = ibuf; (*p++ = (CHAR & *ip++)) != '\0'; )
380                continue;
381        }
382        break;
383    default:
384        buf[0] = '\0';
385        break;
386    }
387       
388}
389
390void
391rechist(fname, ref)
392    Char *fname;
393    int ref;
394{
395    Char    *snum;
396    int     fp, ftmp, oldidfds;
397    struct varent *shist;
398    static Char   *dumphist[] = {STRhistory, STRmhT, 0, 0};
399
400    if (fname == NULL && !ref)
401        return;
402    /*
403     * If $savehist is just set, we use the value of $history
404     * else we use the value in $savehist
405     */
406    if (((snum = varval(STRsavehist)) == STRNULL) &&
407        ((snum = varval(STRhistory)) == STRNULL))
408        snum = STRmaxint;
409
410
411    if (fname == NULL) {
412        if ((fname = varval(STRhistfile)) == STRNULL)
413            fname = Strspl(varval(STRhome), &STRtildothist[1]);
414        else
415            fname = Strsave(fname);
416    }
417    else
418        fname = globone(fname, G_ERROR);
419
420    /*
421     * The 'savehist merge' feature is intended for an environment
422     * with numerous shells beeing in simultaneous use. Imagine
423     * any kind of window system. All these shells 'share' the same
424     * ~/.history file for recording their command line history.
425     * Currently the automatic merge can only succeed when the shells
426     * nicely quit one after another.
427     *
428     * Users that like to nuke their environment require here an atomic
429     *  loadhist-creat-dohist(dumphist)-close
430     * sequence.
431     *
432     * jw.
433     */
434    /*
435     * We need the didfds stuff before loadhist otherwise
436     * exec in a script will fail to print if merge is set.
437     * From: mveksler@iil.intel.com (Veksler Michael)
438     */
439    oldidfds = didfds;
440    didfds = 0;
441    if ((shist = adrof(STRsavehist)) != NULL)
442        if (shist->vec[1] && eq(shist->vec[1], STRmerge))
443            loadhist(fname, 1);
444    fp = creat(short2str(fname), 0600);
445    if (fp == -1) {
446        didfds = oldidfds;
447        return;
448    }
449    ftmp = SHOUT;
450    SHOUT = fp;
451    dumphist[2] = snum;
452    dohist(dumphist, NULL);
453    (void) close(fp);
454    SHOUT = ftmp;
455    didfds = oldidfds;
456    xfree((ptr_t) fname);
457}
458
459
460void
461loadhist(fname, mflg)
462    Char *fname;
463    bool mflg;
464{
465    static Char   *loadhist_cmd[] = {STRsource, NULL, NULL, NULL};
466    loadhist_cmd[1] = mflg ? STRmm : STRmh;
467
468    if (fname != NULL)
469        loadhist_cmd[2] = fname;
470    else if ((fname = varval(STRhistfile)) != STRNULL)
471        loadhist_cmd[2] = fname;
472    else
473        loadhist_cmd[2] = STRtildothist;
474
475    dosource(loadhist_cmd, NULL);
476}
Note: See TracBrowser for help on using the repository browser.