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