1 /* $Header: /src/pub/tcsh/sh.hist.c,v 3.33 2004/12/25 21:15:07 christos Exp $ */
3 * sh.hist.c: Shell history expansions and substitutions
6 * Copyright (c) 1980, 1991 The Regents of the University of California.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
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.
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
35 RCSID("$Id: sh.hist.c,v 3.33 2004/12/25 21:15:07 christos Exp $")
40 extern Char histline[];
43 static int heq __P((struct wordent *, struct wordent *));
44 static void hfree __P((struct Hist *));
45 static void dohist1 __P((struct Hist *, int *, int));
46 static void phist __P((struct Hist *, int));
48 #define HIST_ONLY 0x01
49 #define HIST_SAVE 0x02
50 #define HIST_LOAD 0x04
52 #define HIST_CLEAR 0x10
53 #define HIST_MERGE 0x20
54 #define HIST_TIME 0x40
69 /* throw away null lines */
70 if (sp && sp->next->word[0] == '\n')
72 cp = varval(STRhistory);
81 histlen = histlen * 10 + *p++ - '0';
85 (void) enthist(++eventno, sp, 1, mflg);
86 for (hp = &Histlist; (np = hp->Hnext) != NULL;)
87 if (eventno - np->Href >= histlen || histlen == 0)
88 hp->Hnext = np->Hnext, hfree(np);
95 struct wordent *a0, *b0;
97 struct wordent *a = a0->next, *b = b0->next;
100 if (Strcmp(a->word, b->word) != 0)
105 return (b == b0) ? 1 : 0;
113 enthist(event, lp, docopy, mflg)
119 struct Hist *p = NULL, *pp = &Histlist;
124 if ((dp = varval(STRhistdup)) != STRNULL) {
125 if (eq(dp, STRerase)) {
126 /* masaoki@akebono.tky.hp.com (Kobayashi Masaoki) */
128 for (p = pp; (px = p, p = p->Hnext) != NULL;)
129 if (heq(lp, &(p->Hlex))){
130 px->Hnext = p->Hnext;
131 if (Htime != 0 && p->Htime > Htime)
135 for (p = px->Hnext; p != NULL; p = p->Hnext)
140 else if (eq(dp, STRall)) {
141 for (p = pp; (p = p->Hnext) != NULL;)
142 if (heq(lp, &(p->Hlex))) {
147 else if (eq(dp, STRprev)) {
148 if (pp->Hnext && heq(lp, &(pp->Hnext->Hlex))) {
155 np = p ? p : (struct Hist *) xmalloc((size_t) sizeof(*np));
157 /* Pick up timestamp set by lex() in Htime if reading saved history */
158 if (Htime != (time_t) 0) {
163 (void) time(&(np->Htime));
168 np->Hnum = np->Href = event;
170 copylex(&np->Hlex, lp);
172 np->histline = Strsave(histline);
177 np->Hlex.next = lp->next;
178 lp->next->prev = &np->Hlex;
179 np->Hlex.prev = lp->prev;
180 lp->prev->next = &np->Hlex;
185 while ((p = pp->Hnext) && (p->Htime > np->Htime))
187 while (p && p->Htime == np->Htime)
189 if (heq(&p->Hlex, &np->Hlex))
198 for (p = Histlist.Hnext; p != pp->Hnext; p = p->Hnext)
200 n = p->Hnum; r = p->Href;
201 p->Hnum = np->Hnum; p->Href = np->Href;
202 np->Hnum = n; np->Href = r;
205 np->Hnext = pp->Hnext;
217 xfree((ptr_t) hp->histline);
231 if (getn(varval(STRhistory)) == 0)
235 (void) sigsetmask(sigblock((sigmask_t) 0) & ~sigmask(SIGINT));
237 (void) sigrelse(SIGINT);
239 while (*++vp && **vp == '-') {
266 stderror(ERR_HISTUS, "chrSLMT");
271 if (hflg & HIST_CLEAR) {
272 struct Hist *np, *hp;
273 for (hp = &Histlist; (np = hp->Hnext) != NULL;)
274 hp->Hnext = np->Hnext, hfree(np);
277 if (hflg & (HIST_LOAD | HIST_MERGE)) {
278 loadhist(*vp, (hflg & HIST_MERGE) ? 1 : 0);
281 else if (hflg & HIST_SAVE) {
288 n = getn(varval(STRhistory));
290 dohist1(Histlist.Hnext, &n, hflg);
294 dohist1(hp, np, hflg)
298 int print = (*np) > 0;
300 for (; hp != 0; hp = hp->Hnext) {
302 if ((hflg & HIST_REV) == 0) {
303 dohist1(hp->Hnext, np, hflg);
318 if (hflg & HIST_ONLY) {
320 * Control characters have to be written as is (output_raw).
321 * This way one can preserve special characters (like tab) in
323 * From: mveksler@vnet.ibm.com (Veksler Michael)
326 if (hflg & HIST_TIME)
328 * Make file entry with history time in format:
329 * "+NNNNNNNNNN" (10 digits, left padded with ascii '0')
332 xprintf("#+%010lu\n", hp->Htime);
334 if (HistLit && hp->histline)
335 xprintf("%S\n", hp->histline);
341 Char *cp = str2short("%h\t%T\t%R\n");
343 struct varent *vp = adrof(STRhistory);
345 if (vp && vp->vec != NULL && vp->vec[0] && vp->vec[1])
348 tprintf(FMT_HISTORY, buf, cp, INBUFSIZE, NULL, hp->Htime, (ptr_t) hp);
356 fmthist(fmt, ptr, buf, bufsiz)
362 struct Hist *hp = (struct Hist *) ptr;
365 (void) xsnprintf(buf, bufsiz, "%6d", hp->Hnum);
368 if (HistLit && hp->histline)
369 (void) xsnprintf(buf, bufsiz, "%S", hp->histline);
371 Char ibuf[INBUFSIZE], *ip;
373 (void) sprlex(ibuf, sizeof(ibuf) / sizeof(Char), &hp->Hlex);
377 char xbuf[MB_LEN_MAX];
380 len = one_wctomb(xbuf, CHAR & *ip);
381 if ((size_t)((p - buf) + len) >= bufsiz)
383 memcpy(p, xbuf, len);
385 } while ((CHAR & *ip++) != 0);
386 if (p <= buf + bufsiz - 1)
403 int fp, ftmp, oldidfds;
404 struct varent *shist;
405 static Char *dumphist[] = {STRhistory, STRmhT, 0, 0};
407 if (fname == NULL && !ref)
410 * If $savehist is just set, we use the value of $history
411 * else we use the value in $savehist
413 if (((snum = varval(STRsavehist)) == STRNULL) &&
414 ((snum = varval(STRhistory)) == STRNULL))
419 if ((fname = varval(STRhistfile)) == STRNULL)
420 fname = Strspl(varval(STRhome), &STRtildothist[1]);
422 fname = Strsave(fname);
425 fname = globone(fname, G_ERROR);
428 * The 'savehist merge' feature is intended for an environment
429 * with numerous shells beeing in simultaneous use. Imagine
430 * any kind of window system. All these shells 'share' the same
431 * ~/.history file for recording their command line history.
432 * Currently the automatic merge can only succeed when the shells
433 * nicely quit one after another.
435 * Users that like to nuke their environment require here an atomic
436 * loadhist-creat-dohist(dumphist)-close
442 * We need the didfds stuff before loadhist otherwise
443 * exec in a script will fail to print if merge is set.
444 * From: mveksler@iil.intel.com (Veksler Michael)
448 if ((shist = adrof(STRsavehist)) != NULL && shist->vec != NULL)
449 if (shist->vec[1] && eq(shist->vec[1], STRmerge))
451 fp = creat(short2str(fname), 0600);
459 dohist(dumphist, NULL);
463 xfree((ptr_t) fname);
468 loadhist(fname, mflg)
472 static Char *loadhist_cmd[] = {STRsource, NULL, NULL, NULL};
473 loadhist_cmd[1] = mflg ? STRmm : STRmh;
476 loadhist_cmd[2] = fname;
477 else if ((fname = varval(STRhistfile)) != STRNULL)
478 loadhist_cmd[2] = fname;
480 loadhist_cmd[2] = STRtildothist;
482 dosource(loadhist_cmd, NULL);