1 /* $Header: /src/pub/tcsh/sh.hist.c,v 3.29 2002/06/25 19:02:11 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.29 2002/06/25 19:02:11 christos Exp $")
39 extern bool histvalid
;
40 extern Char histline
[];
43 static bool 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
65 register struct Hist
*hp
, *np
;
66 register int histlen
= 0;
69 /* throw away null lines */
70 if (sp
&& sp
->next
->word
[0] == '\n')
72 cp
= varval(STRhistory
);
74 register Char
*p
= cp
;
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
)
115 register struct wordent
*lp
;
120 struct Hist
*p
= NULL
, *pp
= &Histlist
;
122 register struct Hist
*np
;
125 if ((dp
= varval(STRhistdup
)) != STRNULL
) {
126 if (eq(dp
, STRerase
)) {
127 /* masaoki@akebono.tky.hp.com (Kobayashi Masaoki) */
129 for (p
= pp
; (px
= p
, p
= p
->Hnext
) != NULL
;)
130 if (heq(lp
, &(p
->Hlex
))){
131 px
->Hnext
= p
->Hnext
;
132 if (Htime
!= 0 && p
->Htime
> Htime
)
136 for (p
= px
->Hnext
; p
!= NULL
; p
= p
->Hnext
)
141 else if (eq(dp
, STRall
)) {
142 for (p
= pp
; (p
= p
->Hnext
) != NULL
;)
143 if (heq(lp
, &(p
->Hlex
))) {
148 else if (eq(dp
, STRprev
)) {
149 if (pp
->Hnext
&& heq(lp
, &(pp
->Hnext
->Hlex
))) {
156 np
= p
? p
: (struct Hist
*) xmalloc((size_t) sizeof(*np
));
158 /* Pick up timestamp set by lex() in Htime if reading saved history */
159 if (Htime
!= (time_t) 0) {
164 (void) time(&(np
->Htime
));
169 np
->Hnum
= np
->Href
= event
;
171 copylex(&np
->Hlex
, lp
);
173 np
->histline
= Strsave(histline
);
178 np
->Hlex
.next
= lp
->next
;
179 lp
->next
->prev
= &np
->Hlex
;
180 np
->Hlex
.prev
= lp
->prev
;
181 lp
->prev
->next
= &np
->Hlex
;
186 while ((p
= pp
->Hnext
) && (p
->Htime
> np
->Htime
))
188 while (p
&& p
->Htime
== np
->Htime
)
190 if (heq(&p
->Hlex
, &np
->Hlex
))
199 for (p
= Histlist
.Hnext
; p
!= pp
->Hnext
; p
= p
->Hnext
)
201 n
= p
->Hnum
; r
= p
->Href
;
202 p
->Hnum
= np
->Hnum
; p
->Href
= np
->Href
;
203 np
->Hnum
= n
; np
->Href
= r
;
206 np
->Hnext
= pp
->Hnext
;
213 register struct Hist
*hp
;
218 xfree((ptr_t
) hp
->histline
);
232 if (getn(varval(STRhistory
)) == 0)
236 (void) sigsetmask(sigblock((sigmask_t
) 0) & ~sigmask(SIGINT
));
238 (void) sigrelse(SIGINT
);
240 while (*++vp
&& **vp
== '-') {
267 stderror(ERR_HISTUS
, "chrSLMT");
272 if (hflg
& HIST_CLEAR
) {
273 struct Hist
*np
, *hp
;
274 for (hp
= &Histlist
; (np
= hp
->Hnext
) != NULL
;)
275 hp
->Hnext
= np
->Hnext
, hfree(np
);
278 if (hflg
& (HIST_LOAD
| HIST_MERGE
)) {
279 loadhist(*vp
, (hflg
& HIST_MERGE
) ? 1 : 0);
282 else if (hflg
& HIST_SAVE
) {
289 n
= getn(varval(STRhistory
));
291 dohist1(Histlist
.Hnext
, &n
, hflg
);
295 dohist1(hp
, np
, hflg
)
299 bool print
= (*np
) > 0;
301 for (; hp
!= 0; hp
= hp
->Hnext
) {
303 if ((hflg
& HIST_REV
) == 0) {
304 dohist1(hp
->Hnext
, np
, hflg
);
316 register struct Hist
*hp
;
319 extern bool output_raw
;
320 if (hflg
& HIST_ONLY
) {
322 * Control characters have to be written as is (output_raw).
323 * This way one can preserve special characters (like tab) in
325 * From: mveksler@vnet.ibm.com (Veksler Michael)
328 if (hflg
& HIST_TIME
)
330 * Make file entry with history time in format:
331 * "+NNNNNNNNNN" (10 digits, left padded with ascii '0')
334 xprintf("#+%010lu\n", hp
->Htime
);
336 if (HistLit
&& hp
->histline
)
337 xprintf("%S\n", hp
->histline
);
343 Char
*cp
= str2short("%h\t%T\t%R\n");
345 struct varent
*vp
= adrof(STRhistory
);
347 if (vp
&& vp
->vec
!= NULL
&& vp
->vec
[0] && vp
->vec
[1])
350 tprintf(FMT_HISTORY
, buf
, cp
, INBUFSIZE
, NULL
, hp
->Htime
, (ptr_t
) hp
);
358 fmthist(fmt
, ptr
, buf
, bufsiz
)
364 struct Hist
*hp
= (struct Hist
*) ptr
;
367 (void) xsnprintf(buf
, bufsiz
, "%6d", hp
->Hnum
);
370 if (HistLit
&& hp
->histline
)
371 (void) xsnprintf(buf
, bufsiz
, "%S", hp
->histline
);
373 Char ibuf
[INBUFSIZE
], *ip
;
375 (void) sprlex(ibuf
, sizeof(ibuf
) / sizeof(Char
), &hp
->Hlex
);
376 for (p
= buf
, ip
= ibuf
; (*p
++ = (CHAR
& *ip
++)) != '\0'; )
393 int fp
, ftmp
, oldidfds
;
394 struct varent
*shist
;
395 static Char
*dumphist
[] = {STRhistory
, STRmhT
, 0, 0};
397 if (fname
== NULL
&& !ref
)
400 * If $savehist is just set, we use the value of $history
401 * else we use the value in $savehist
403 if (((snum
= varval(STRsavehist
)) == STRNULL
) &&
404 ((snum
= varval(STRhistory
)) == STRNULL
))
409 if ((fname
= varval(STRhistfile
)) == STRNULL
)
410 fname
= Strspl(varval(STRhome
), &STRtildothist
[1]);
412 fname
= Strsave(fname
);
415 fname
= globone(fname
, G_ERROR
);
418 * The 'savehist merge' feature is intended for an environment
419 * with numerous shells beeing in simultaneous use. Imagine
420 * any kind of window system. All these shells 'share' the same
421 * ~/.history file for recording their command line history.
422 * Currently the automatic merge can only succeed when the shells
423 * nicely quit one after another.
425 * Users that like to nuke their environment require here an atomic
426 * loadhist-creat-dohist(dumphist)-close
432 * We need the didfds stuff before loadhist otherwise
433 * exec in a script will fail to print if merge is set.
434 * From: mveksler@iil.intel.com (Veksler Michael)
438 if ((shist
= adrof(STRsavehist
)) != NULL
&& shist
->vec
!= NULL
)
439 if (shist
->vec
[1] && eq(shist
->vec
[1], STRmerge
))
441 fp
= creat(short2str(fname
), 0600);
449 dohist(dumphist
, NULL
);
453 xfree((ptr_t
) fname
);
458 loadhist(fname
, mflg
)
462 static Char
*loadhist_cmd
[] = {STRsource
, NULL
, NULL
, NULL
};
463 loadhist_cmd
[1] = mflg
? STRmm
: STRmh
;
466 loadhist_cmd
[2] = fname
;
467 else if ((fname
= varval(STRhistfile
)) != STRNULL
)
468 loadhist_cmd
[2] = fname
;
470 loadhist_cmd
[2] = STRtildothist
;
472 dosource(loadhist_cmd
, NULL
);