sh.hist.c revision 167465
1153761Swollman/* $Header: /p/tcsh/cvsroot/tcsh/sh.hist.c,v 3.40 2007/03/01 17:14:51 christos Exp $ */ 2223629Sedwin/* 3192886Sedwin * sh.hist.c: Shell history expansions and substitutions 4192886Sedwin */ 564499Swollman/*- 62742Swollman * Copyright (c) 1980, 1991 The Regents of the University of California. 72742Swollman * All rights reserved. 82742Swollman * 92742Swollman * Redistribution and use in source and binary forms, with or without 10158421Swollman * modification, are permitted provided that the following conditions 112742Swollman * are met: 12158421Swollman * 1. Redistributions of source code must retain the above copyright 13158421Swollman * notice, this list of conditions and the following disclaimer. 142742Swollman * 2. Redistributions in binary form must reproduce the above copyright 1586222Swollman * notice, this list of conditions and the following disclaimer in the 1620094Swollman * documentation and/or other materials provided with the distribution. 1720094Swollman * 3. Neither the name of the University nor the names of its contributors 1820094Swollman * may be used to endorse or promote products derived from this software 1920094Swollman * without specific prior written permission. 2020094Swollman * 21158421Swollman * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22158421Swollman * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2320094Swollman * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2443543Swollman * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 252742Swollman * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2643543Swollman * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2743543Swollman * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2843543Swollman * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2943543Swollman * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30121098Swollman * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31121098Swollman * SUCH DAMAGE. 32121098Swollman */ 33121098Swollman#include "sh.h" 3443543Swollman 3543543SwollmanRCSID("$tcsh: sh.hist.c,v 3.40 2007/03/01 17:14:51 christos Exp $") 3643543Swollman 3743543Swollman#include "tc.h" 3843543Swollman 3943543Swollmanextern int histvalid; 402742Swollmanextern struct Strbuf histline; 412742SwollmanChar HistLit = 0; 4219878Swollman 43114173Swollmanstatic int heq (const struct wordent *, const struct wordent *); 44114173Swollmanstatic void hfree (struct Hist *); 45114173Swollmanstatic void dohist1 (struct Hist *, int *, int); 46114173Swollmanstatic void phist (struct Hist *, int); 47114173Swollman 48114173Swollman#define HIST_ONLY 0x01 49114173Swollman#define HIST_SAVE 0x02 50114173Swollman#define HIST_LOAD 0x04 51114173Swollman#define HIST_REV 0x08 52114173Swollman#define HIST_CLEAR 0x10 53114173Swollman#define HIST_MERGE 0x20 54114173Swollman#define HIST_TIME 0x40 55114173Swollman 56114173Swollman/* 572742Swollman * C shell 582742Swollman */ 5958787Sru 602742Swollmanvoid 61149514Swollmansavehist(struct wordent *sp, int mflg) 6214343Swollman{ 639908Swollman struct Hist *hp, *np; 649908Swollman int histlen = 0; 659908Swollman Char *cp; 669908Swollman 679908Swollman /* throw away null lines */ 689908Swollman if (sp && sp->next->word[0] == '\n') 699908Swollman return; 709908Swollman cp = varval(STRhistory); 719908Swollman while (*cp) { 729908Swollman if (!Isdigit(*cp)) { 7314343Swollman histlen = 0; 7414343Swollman break; 759908Swollman } 769908Swollman histlen = histlen * 10 + *cp++ - '0'; 779908Swollman } 789908Swollman if (sp) 799908Swollman (void) enthist(++eventno, sp, 1, mflg); 809908Swollman for (hp = &Histlist; (np = hp->Hnext) != NULL;) 819908Swollman if (eventno - np->Href >= histlen || histlen == 0) 8219878Swollman hp->Hnext = np->Hnext, hfree(np); 832742Swollman else 842742Swollman hp = np; 8543014Swollman} 862742Swollman 87149514Swollmanstatic int 882742Swollmanheq(const struct wordent *a0, const struct wordent *b0) 892742Swollman{ 902742Swollman const struct wordent *a = a0->next, *b = b0->next; 912742Swollman 922742Swollman for (;;) { 932742Swollman if (Strcmp(a->word, b->word) != 0) 942742Swollman return 0; 9521217Swollman a = a->next; 962742Swollman b = b->next; 972742Swollman if (a == a0) 982742Swollman return (b == b0) ? 1 : 0; 992742Swollman if (b == b0) 1002742Swollman return 0; 1012742Swollman } 1022742Swollman} 10321217Swollman 1042742Swollman 1052742Swollmanstruct Hist * 1062742Swollmanenthist(int event, struct wordent *lp, int docopy, int mflg) 1072742Swollman{ 108149514Swollman struct Hist *p = NULL, *pp = &Histlist; 1092742Swollman int n, r; 1102742Swollman struct Hist *np; 1112742Swollman const Char *dp; 1122742Swollman 11358787Sru if ((dp = varval(STRhistdup)) != STRNULL) { 11458787Sru if (eq(dp, STRerase)) { 1152742Swollman /* masaoki@akebono.tky.hp.com (Kobayashi Masaoki) */ 1162742Swollman struct Hist *px; 11758787Sru for (p = pp; (px = p, p = p->Hnext) != NULL;) 1182742Swollman if (heq(lp, &(p->Hlex))){ 11958787Sru px->Hnext = p->Hnext; 12058787Sru if (Htime != 0 && p->Htime > Htime) 12158787Sru Htime = p->Htime; 1222742Swollman n = p->Href; 12358787Sru hfree(p); 12458787Sru for (p = px->Hnext; p != NULL; p = p->Hnext) 1252742Swollman p->Href = n--; 1262742Swollman break; 1272742Swollman } 1282742Swollman } 12958787Sru else if (eq(dp, STRall)) { 1302742Swollman for (p = pp; (p = p->Hnext) != NULL;) 1312742Swollman if (heq(lp, &(p->Hlex))) { 13258787Sru eventno--; 13358787Sru break; 1342742Swollman } 135136638Swollman } 13617200Swollman else if (eq(dp, STRprev)) { 13743543Swollman if (pp->Hnext && heq(lp, &(pp->Hnext->Hlex))) { 13858787Sru p = pp->Hnext; 13917200Swollman eventno--; 14017200Swollman } 14117200Swollman } 14217200Swollman } 143121098Swollman 144121098Swollman np = p ? p : xmalloc(sizeof(*np)); 145121098Swollman 146121098Swollman /* Pick up timestamp set by lex() in Htime if reading saved history */ 147136638Swollman if (Htime != 0) { 148121098Swollman np->Htime = Htime; 149221092Sedwin Htime = 0; 150121098Swollman } 15117200Swollman else 152121098Swollman (void) time(&(np->Htime)); 153121098Swollman 154121098Swollman if (p == np) 155121098Swollman return np; 156121098Swollman 157121098Swollman np->Hnum = np->Href = event; 158121098Swollman if (docopy) { 159121098Swollman copylex(&np->Hlex, lp); 160121098Swollman if (histvalid) 161121098Swollman np->histline = Strsave(histline.s); 16219878Swollman else 16319878Swollman np->histline = NULL; 16419878Swollman } 16519878Swollman else { 16619878Swollman np->Hlex.next = lp->next; 16719878Swollman lp->next->prev = &np->Hlex; 16819878Swollman np->Hlex.prev = lp->prev; 1692742Swollman lp->prev->next = &np->Hlex; 1702742Swollman np->histline = NULL; 1712742Swollman } 1722742Swollman if (mflg) 1732742Swollman { 174149514Swollman while ((p = pp->Hnext) && (p->Htime > np->Htime)) 1752742Swollman pp = p; 1762742Swollman while (p && p->Htime == np->Htime) 1772742Swollman { 1782742Swollman if (heq(&p->Hlex, &np->Hlex)) 179149514Swollman { 18043014Swollman eventno--; 18143014Swollman hfree(np); 18243014Swollman return (p); 18343014Swollman } 18443014Swollman pp = p; 18558787Sru p = p->Hnext; 18658787Sru } 18758787Sru for (p = Histlist.Hnext; p != pp->Hnext; p = p->Hnext) 18858787Sru { 1892742Swollman n = p->Hnum; r = p->Href; 19075267Swollman p->Hnum = np->Hnum; p->Href = np->Href; 19167578Swollman np->Hnum = n; np->Href = r; 19267578Swollman } 19367578Swollman } 19467578Swollman np->Hnext = pp->Hnext; 19567578Swollman pp->Hnext = np; 19675267Swollman return (np); 19767578Swollman} 19858787Sru 19967578Swollmanstatic void 20067578Swollmanhfree(struct Hist *hp) 20167578Swollman{ 20267578Swollman 20367578Swollman freelex(&hp->Hlex); 20467578Swollman if (hp->histline) 20567578Swollman xfree(hp->histline); 20667578Swollman xfree(hp); 20767578Swollman} 20867578Swollman 20967578Swollman 210149514Swollman/*ARGSUSED*/ 21158787Sruvoid 212149514Swollmandohist(Char **vp, struct command *c) 21358787Sru{ 21458787Sru int n, hflg = 0; 21558787Sru 21693799Swollman USE(c); 21758787Sru if (getn(varval(STRhistory)) == 0) 218149514Swollman return; 21943014Swollman while (*++vp && **vp == '-') { 22043014Swollman Char *vp2 = *vp; 22143014Swollman 22243014Swollman while (*++vp2) 22343014Swollman switch (*vp2) { 22443014Swollman case 'c': 2252742Swollman hflg |= HIST_CLEAR; 226158421Swollman break; 2272742Swollman case 'h': 228158421Swollman hflg |= HIST_ONLY; 2292742Swollman break; 230158421Swollman case 'r': 231158421Swollman hflg |= HIST_REV; 23230711Swollman break; 2332742Swollman case 'S': 2342742Swollman hflg |= HIST_SAVE; 2352742Swollman break; 2362742Swollman case 'L': 23730711Swollman hflg |= HIST_LOAD; 2382742Swollman break; 23917200Swollman case 'M': 24017200Swollman hflg |= HIST_MERGE; 24117200Swollman break; 2422742Swollman case 'T': 243158421Swollman hflg |= HIST_TIME; 2442742Swollman break; 24530711Swollman default: 2462742Swollman stderror(ERR_HISTUS, "chrSLMT"); 24758787Sru break; 24858787Sru } 249158421Swollman } 25058787Sru 25117200Swollman if (hflg & HIST_CLEAR) { 2522742Swollman struct Hist *np, *hp; 25317200Swollman for (hp = &Histlist; (np = hp->Hnext) != NULL;) 254158421Swollman hp->Hnext = np->Hnext, hfree(np); 255158421Swollman } 25686222Swollman 25786222Swollman if (hflg & (HIST_LOAD | HIST_MERGE)) 25886222Swollman loadhist(*vp, (hflg & HIST_MERGE) ? 1 : 0); 25986222Swollman else if (hflg & HIST_SAVE) 26086222Swollman rechist(*vp, 1); 26186222Swollman else { 2622742Swollman if (*vp) 263149514Swollman n = getn(*vp); 264169811Swollman else { 265149514Swollman n = getn(varval(STRhistory)); 266169811Swollman } 267149514Swollman dohist1(Histlist.Hnext, &n, hflg); 268169811Swollman } 269149514Swollman} 270149514Swollman 271169811Swollmanstatic void 272149514Swollmandohist1(struct Hist *hp, int *np, int hflg) 273149514Swollman{ 274149514Swollman int print = (*np) > 0; 275169811Swollman 276149514Swollman for (; hp != 0; hp = hp->Hnext) { 277149514Swollman if (setintr) { 278149514Swollman int old_pintr_disabled; 279149514Swollman 280149514Swollman pintr_push_enable(&old_pintr_disabled); 281149514Swollman cleanup_until(&old_pintr_disabled); 282169811Swollman } 283169811Swollman (*np)--; 284169811Swollman if ((hflg & HIST_REV) == 0) { 285149514Swollman dohist1(hp->Hnext, np, hflg); 286169811Swollman if (print) 287169811Swollman phist(hp, hflg); 288169811Swollman return; 289169811Swollman } 290149514Swollman if (*np >= 0) 291149514Swollman phist(hp, hflg); 29258787Sru } 29358787Sru} 29458787Sru 29558787Srustatic void 29658787Sruphist(struct Hist *hp, int hflg) 29758787Sru{ 29858787Sru if (hflg & HIST_ONLY) { 29958787Sru int old_output_raw; 30058787Sru 30158787Sru /* 30258787Sru * Control characters have to be written as is (output_raw). 30358787Sru * This way one can preserve special characters (like tab) in 30458787Sru * the history file. 30558787Sru * From: mveksler@vnet.ibm.com (Veksler Michael) 30617200Swollman */ 30717200Swollman old_output_raw = output_raw; 30817200Swollman output_raw = 1; 30917200Swollman cleanup_push(&old_output_raw, output_raw_restore); 31017200Swollman if (hflg & HIST_TIME) 31117200Swollman /* 31217200Swollman * Make file entry with history time in format: 31317200Swollman * "+NNNNNNNNNN" (10 digits, left padded with ascii '0') 3142742Swollman */ 31543014Swollman 3162742Swollman xprintf("#+%010lu\n", (unsigned long)hp->Htime); 3172742Swollman 31843014Swollman if (HistLit && hp->histline) 3192742Swollman xprintf("%S\n", hp->histline); 3202742Swollman else 32143014Swollman prlex(&hp->Hlex); 3222742Swollman cleanup_until(&old_output_raw); 3232742Swollman } 32443014Swollman else { 3252742Swollman Char *cp = str2short("%h\t%T\t%R\n"); 3262742Swollman Char *p; 32743014Swollman struct varent *vp = adrof(STRhistory); 3282742Swollman 32943014Swollman if (vp && vp->vec != NULL && vp->vec[0] && vp->vec[1]) 3302742Swollman cp = vp->vec[1]; 33143014Swollman 3322742Swollman p = tprintf(FMT_HISTORY, cp, NULL, hp->Htime, hp); 3332742Swollman cleanup_push(p, xfree); 33443014Swollman for (cp = p; *cp;) 3352742Swollman xputwchar(*cp++); 33658787Sru cleanup_until(p); 33743014Swollman } 3382742Swollman} 3392742Swollman 34043014Swollman 3412742Swollmanchar * 34243014Swollmanfmthist(int fmt, ptr_t ptr) 3432742Swollman{ 34443014Swollman struct Hist *hp = ptr; 3452742Swollman char *buf; 34643014Swollman 3472742Swollman switch (fmt) { 34843014Swollman case 'h': 3492742Swollman return xasprintf("%6d", hp->Hnum); 35043014Swollman case 'R': 3512742Swollman if (HistLit && hp->histline) 35243014Swollman return xasprintf("%S", hp->histline); 3532742Swollman else { 35443014Swollman Char *istr, *ip; 35543014Swollman char *p; 35643014Swollman 35743014Swollman istr = sprlex(&hp->Hlex); 35843014Swollman buf = xmalloc(Strlen(istr) * MB_LEN_MAX + 1); 35919878Swollman 3602742Swollman for (p = buf, ip = istr; *ip != '\0'; ip++) 36143014Swollman p += one_wctomb(p, CHAR & *ip); 36219878Swollman 36343014Swollman *p = '\0'; 3642742Swollman xfree(istr); 36543014Swollman return buf; 36643014Swollman } 36743014Swollman default: 36843014Swollman buf = xmalloc(1); 36943014Swollman buf[0] = '\0'; 37043014Swollman return buf; 37143014Swollman } 3722742Swollman} 37319878Swollman 3742742Swollmanvoid 3752742Swollmanrechist(Char *fname, int ref) 37643014Swollman{ 3772742Swollman Char *snum; 37843014Swollman int fp, ftmp, oldidfds; 37943014Swollman struct varent *shist; 3802742Swollman static Char *dumphist[] = {STRhistory, STRmhT, 0, 0}; 38143014Swollman 38243014Swollman if (fname == NULL && !ref) 38343014Swollman return; 38443014Swollman /* 38543014Swollman * If $savehist is just set, we use the value of $history 3862742Swollman * else we use the value in $savehist 38743014Swollman */ 38843014Swollman if (((snum = varval(STRsavehist)) == STRNULL) && 38943014Swollman ((snum = varval(STRhistory)) == STRNULL)) 39043014Swollman snum = STRmaxint; 3912742Swollman 39243014Swollman 3932742Swollman if (fname == NULL) { 39443014Swollman if ((fname = varval(STRhistfile)) == STRNULL) 39543014Swollman fname = Strspl(varval(STRhome), &STRtildothist[1]); 39643014Swollman else 39743014Swollman fname = Strsave(fname); 3982742Swollman } 39943014Swollman else 40043014Swollman fname = globone(fname, G_ERROR); 40143014Swollman cleanup_push(fname, xfree); 40243014Swollman 4032742Swollman /* 40443014Swollman * The 'savehist merge' feature is intended for an environment 40517200Swollman * with numerous shells being in simultaneous use. Imagine 40643014Swollman * any kind of window system. All these shells 'share' the same 40743014Swollman * ~/.history file for recording their command line history. 40843014Swollman * Currently the automatic merge can only succeed when the shells 4092742Swollman * nicely quit one after another. 4102742Swollman * 41143014Swollman * Users that like to nuke their environment require here an atomic 41243014Swollman * loadhist-creat-dohist(dumphist)-close 41343014Swollman * sequence. 41443014Swollman * 4159908Swollman * jw. 4169908Swollman */ 41743014Swollman /* 41843014Swollman * We need the didfds stuff before loadhist otherwise 41943014Swollman * exec in a script will fail to print if merge is set. 4209908Swollman * From: mveksler@iil.intel.com (Veksler Michael) 42143014Swollman */ 42217200Swollman oldidfds = didfds; 4232742Swollman didfds = 0; 4242742Swollman if ((shist = adrof(STRsavehist)) != NULL && shist->vec != NULL) 425158421Swollman if (shist->vec[1] && eq(shist->vec[1], STRmerge)) 42617200Swollman loadhist(fname, 1); 42717200Swollman fp = xcreat(short2str(fname), 0600); 4289908Swollman if (fp == -1) { 42917200Swollman didfds = oldidfds; 430163302Sru cleanup_until(fname); 431163302Sru return; 432163302Sru } 43386222Swollman ftmp = SHOUT; 43486222Swollman SHOUT = fp; 43543014Swollman dumphist[2] = snum; 43619878Swollman dohist(dumphist, NULL); 43717200Swollman xclose(fp); 43817200Swollman SHOUT = ftmp; 4392742Swollman didfds = oldidfds; 44017200Swollman cleanup_until(fname); 4412742Swollman} 44217200Swollman 44317200Swollman 44417200Swollmanvoid 44517200Swollmanloadhist(Char *fname, int mflg) 4462742Swollman{ 4472742Swollman static Char *loadhist_cmd[] = {STRsource, NULL, NULL, NULL}; 4482742Swollman loadhist_cmd[1] = mflg ? STRmm : STRmh; 449171948Sedwin 4502742Swollman if (fname != NULL) 45117200Swollman loadhist_cmd[2] = fname; 45217200Swollman else if ((fname = varval(STRhistfile)) != STRNULL) 4539908Swollman loadhist_cmd[2] = fname; 4549908Swollman else 45519878Swollman loadhist_cmd[2] = STRtildothist; 45617200Swollman 45717200Swollman dosource(loadhist_cmd, NULL); 45817200Swollman} 45919878Swollman