Пример #1
0
Файл: history.c Проект: att/ast
//
// Copy the last <n> commands to a new file and make this the history file.
//
static History_t *hist_trim(History_t *hp, int n) {
    char *cp;
    int incmd = 1, c = 0;
    History_t *hist_new, *hist_old = hp;
    char *buff, *endbuff, *tmpname = NULL;
    off_t oldp, newp;
    struct stat statb;

    unlink(hist_old->histname);
    if (access(hist_old->histname, F_OK) >= 0) {
        // The unlink can fail on windows 95.
        int fd;
        char *last, *name = hist_old->histname;
        sh_close(sffileno(hist_old->histfp));
        last = strrchr(name, '/');
        if (last) {
            *last = 0;
            tmpname = ast_temp_file(name, "hist", &fd, 0);
            *last = '/';
        } else {
            tmpname = ast_temp_file(".", "hist", &fd, 0);
        }
        if (!tmpname) {
            errormsg(SH_DICT, ERROR_exit(1), e_create, "hist");
            __builtin_unreachable();
        }
        close(fd);
        if (rename(name, tmpname) < 0) {
            free(tmpname);
            tmpname = name;
        }
        fd = open(tmpname, O_RDONLY | O_CLOEXEC);
        // What happens if this fails and returns -1? Coverity Scan #310940.
        (void)sfsetfd(hist_old->histfp, fd);
        if (tmpname == name) {
            free(tmpname);
            tmpname = NULL;
        }
    }
    hist_ptr = NULL;
    if (fstat(sffileno(hist_old->histfp), &statb) >= 0) {
        histinit = 1;
        histmode = statb.st_mode;
    }
    if (!sh_histinit(hp->histshell)) {
        // Use the old history file.
        hist_ptr = hist_old;
        return hist_ptr;
    }
    hist_new = hist_ptr;
    hist_ptr = hist_old;
    if (--n < 0) n = 0;
    newp = hist_seek(hist_old, ++n);
    while (1) {
        if (!incmd) {
            c = hist_ind(hist_new, ++hist_new->histind);
            hist_new->histcmds[c] = hist_new->histcnt;
            if (hist_new->histcnt > hist_new->histmarker + HIST_BSIZE / 2) {
                char locbuff[HIST_MARKSZ];
                hist_marker(locbuff, hist_new->histind);
                sfwrite(hist_new->histfp, locbuff, HIST_MARKSZ);
                hist_new->histcnt += HIST_MARKSZ;
                hist_new->histmarker = hist_new->histcmds[hist_ind(hist_new, c)] =
                    hist_new->histcnt;
            }
            oldp = newp;
            newp = hist_seek(hist_old, ++n);
            if (newp <= oldp) break;
        }
        if (!(buff = (char *)sfreserve(hist_old->histfp, SF_UNBOUND, 0))) break;
        *(endbuff = (cp = buff) + sfvalue(hist_old->histfp)) = 0;
        // Copy to null byte.
        incmd = 0;
        cp += strlen(cp) + 1;  // point past the terminating null
        if (cp > endbuff) {
            incmd = 1;
        } else if (*cp == 0) {
            cp++;
        }
        if (cp > endbuff) cp = endbuff;
        c = cp - buff;
        hist_new->histcnt += c;
        sfwrite(hist_new->histfp, buff, c);
    }
    hist_cancel(hist_new);
    sfclose(hist_old->histfp);
    if (tmpname) {
        unlink(tmpname);
        free(tmpname);
    }
    free(hist_old);
    hist_ptr = hist_new;
    return hist_ptr;
}
Пример #2
0
Файл: history.c Проект: att/ast
//
// This routine reads the history file from the present position to the end-of-file and puts the
// information in the in-core history table. Note that HIST_CMDNO is only recognized at the
// beginning of a command and that HIST_UNDO as the first character of a command is skipped unless
// it is followed by 0.  If followed by 0 then it cancels the previous command.
//
void hist_eof(History_t *hp) {
    char *cp, *first, *endbuff;
    int n;
    int incmd = 0;
    int skip = 0;
    int oldind = hp->histind;
    off_t count = hp->histcnt;
    off_t last = sfseek(hp->histfp, 0, SEEK_END);

    if (last < count) {
        last = -1;
        count = 2 + HIST_MARKSZ;
        if ((hp->histind -= hp->histsize) < 0) hp->histind = 1;
    }

again:
    sfseek(hp->histfp, count, SEEK_SET);
    while ((cp = (char *)sfreserve(hp->histfp, SF_UNBOUND, 0))) {
        n = sfvalue(hp->histfp);
        endbuff = cp + n;
        first = cp += skip;
        while (1) {
            while (!incmd) {
                if (cp > first) {
                    count += (cp - first);
                    n = hist_ind(hp, ++hp->histind);
#if 0
// TODO: Figure out if this should be enabled. Originally excluded via `#ifdef future`.
                    if (count == hp->histcmds[n]) {
                        sfprintf(sfstderr, "count match n=%d\n", n);
                        if (histinit) {
                            histinit = 0;
                            return;
                        }
                    } else if (n >= histinit)
#endif
                    hp->histcmds[n] = count;
                    first = cp;
                }
                switch (*((unsigned char *)(cp++))) {
                    case HIST_CMDNO: {
                        if (*cp == 0) {
                            hp->histmarker = count + 2;
                            cp += (HIST_MARKSZ - 1);
                            hp->histind--;
                            if (!histinit && (cp <= endbuff)) {
                                unsigned char *marker = (unsigned char *)(cp - 4);
                                hp->histind =
                                    ((marker[0] << 16) | (marker[1] << 8) | (marker[2] - 1));
                            }
                        }
                        break;
                    }
                    case HIST_UNDO: {
                        if (*cp == 0) {
                            cp += 1;
                            hp->histind -= 2;
                        }
                        break;
                    }
                    default: {
                        cp--;
                        incmd = 1;
                    }
                }
                if (cp >= endbuff) {
                    goto refill;
                }
            }
            first = cp;
            while (*cp) {
                if (++cp >= endbuff) goto refill;
            }
            incmd = 0;
            while (*cp == 0) {
                if (++cp >= endbuff) goto refill;
            }
        }
    refill:
        count += (cp - first);
        skip = (cp - endbuff);
        if (!incmd && !skip) hp->histcmds[hist_ind(hp, ++hp->histind)] = count;
    }
    hp->histcnt = count;
    if (incmd && last) {
        sfputc(hp->histfp, 0);
        hist_cancel(hp);
        count = 2;
        skip = 0;
        oldind -= hp->histind;
        hp->histind = hp->histind - hp->histsize + oldind + 2;
        if (hp->histind < 0) hp->histind = 1;
        if (last < 0) {
            char buff[HIST_MARKSZ];
            int fd = open(hp->histname, O_RDWR | O_CLOEXEC);
            if (fd >= 0) {
                hist_marker(buff, hp->histind);
                write(fd, (char *)hist_stamp, 2);
                write(fd, buff, HIST_MARKSZ);
                sh_close(fd);
            }
        }
        last = 0;
        goto again;
    }
}
Пример #3
0
int	b_hist(int argc,char *argv[], void *extra)
{
	register History_t *hp;
	register char *arg;
	register int flag,fdo;
	register Shell_t *shp = ((Shbltin_t*)extra)->shp;
	Sfio_t *outfile;
	char *fname;
	int range[2], incr, index2, indx= -1;
	char *edit = 0;		/* name of editor */
	char *replace = 0;		/* replace old=new */
	int lflag = 0, nflag = 0, rflag = 0;
#if SHOPT_HISTEXPAND
	int pflag = 0;
#endif
	Histloc_t location;
	NOT_USED(argc);
	if(!sh_histinit((void*)shp))
		errormsg(SH_DICT,ERROR_system(1),e_histopen);
	hp = shp->gd->hist_ptr;
	while((flag = optget(argv,sh_opthist))) switch(flag)
	{
	    case 'e':
		edit = opt_info.arg;
		break;
	    case 'n':
		nflag++;
		break;
	    case 'l':
		lflag++;
		break;
	    case 'r':
		rflag++;
		break;
	    case 's':
		edit = "-";
		break;
#if SHOPT_HISTEXPAND
	    case 'p':
		pflag++;
		break;
#endif
	    case 'N':
		if(indx<=0)
		{
			if((flag = hist_max(hp) - opt_info.num-1) < 0)
				flag = 1;
			range[++indx] = flag;
			break;
		}
	    case ':':
		errormsg(SH_DICT,2, "%s", opt_info.arg);
		break;
	    case '?':
		errormsg(SH_DICT,ERROR_usage(2), "%s", opt_info.arg);
		break;
	}
	if(error_info.errors)
		errormsg(SH_DICT,ERROR_usage(2),"%s",optusage((char*)0));
	argv += (opt_info.index-1);
#if SHOPT_HISTEXPAND
	if(pflag)
	{
		hist_cancel(hp);
		pflag = 0;
		while(arg=argv[1])
		{
			flag = hist_expand(arg,&replace);
			if(!(flag & HIST_ERROR))
				sfputr(sfstdout, replace, '\n');
			else
				pflag = 1;
			if(replace)
				free(replace);
			argv++;
		}
		return pflag;
	}
#endif
	flag = indx;
	while(flag<1 && (arg=argv[1]))
	{
		/* look for old=new argument */
		if(!replace && strchr(arg+1,'='))
		{
			replace = arg;
			argv++;
			continue;
		}
		else if(isdigit(*arg) || *arg == '-')
		{
			/* see if completely numeric */
			do	arg++;
			while(isdigit(*arg));
			if(*arg==0)
			{
				arg = argv[1];
				range[++flag] = (int)strtol(arg, (char**)0, 10);
				if(*arg == '-')
					range[flag] += (hist_max(hp)-1);
				argv++;
				continue;
			}
		}
		/* search for last line starting with string */
		location = hist_find(hp,argv[1],hist_max(hp)-1,0,-1);
		if((range[++flag] = location.hist_command) < 0)
			errormsg(SH_DICT,ERROR_exit(1),e_found,argv[1]);
		argv++;
	}
	if(flag <0)
	{
		/* set default starting range */
		if(lflag)
		{
			flag = hist_max(hp)-16;
			if(flag<1)
				flag = 1;
		}
		else
			flag = hist_max(hp)-2;
		range[0] = flag;
		flag = 0;
	}
	index2 = hist_min(hp);
	if(range[0]<index2)
		range[0] = index2;
	if(flag==0)
		/* set default termination range */
		range[1] = ((lflag && !edit)?hist_max(hp)-1:range[0]);
	if(range[1]>=(flag=(hist_max(hp) - !lflag)))
		range[1] = flag;
	/* check for valid ranges */
	if(range[1]<index2 || range[0]>=flag)
		errormsg(SH_DICT,ERROR_exit(1),e_badrange,range[0],range[1]);
	if(edit && *edit=='-' && range[0]!=range[1])
		errormsg(SH_DICT,ERROR_exit(1),e_eneedsarg);
	/* now list commands from range[rflag] to range[1-rflag] */
	incr = 1;
	flag = rflag>0;
	if(range[1-flag] < range[flag])
		incr = -1;
	if(lflag)
	{
		outfile = sfstdout;
		arg = "\n\t";
	}
	else
	{
		if(!(fname=pathtmp(NIL(char*),0,0,NIL(int*))))
			errormsg(SH_DICT,ERROR_exit(1),e_create,"");
		if((fdo=open(fname,O_CREAT|O_RDWR,S_IRUSR|S_IWUSR)) < 0)
			errormsg(SH_DICT,ERROR_system(1),e_create,fname);
		outfile= sfnew(NIL(Sfio_t*),shp->outbuff,IOBSIZE,fdo,SF_WRITE);
		arg = "\n";
		nflag++;
	}
	while(1)
	{
		if(nflag==0)
			sfprintf(outfile,"%d\t",range[flag]);
		else if(lflag)
			sfputc(outfile,'\t');
		hist_list(shp->gd->hist_ptr,outfile,hist_tell(shp->gd->hist_ptr,range[flag]),0,arg);
		if(lflag)
			sh_sigcheck(shp);
		if(range[flag] == range[1-flag])
			break;
		range[flag] += incr;
	}
	if(lflag)
		return(0);
	sfclose(outfile);
	hist_eof(hp);
	arg = edit;
	if(!arg && !(arg=nv_getval(sh_scoped(shp,HISTEDIT))) && !(arg=nv_getval(sh_scoped(shp,FCEDNOD))))
		arg = (char*)e_defedit;
#ifdef apollo
	/*
	 * Code to support the FC using the pad editor.
	 * Exampled of how to use: HISTEDIT=pad
	 */
	if (strcmp (arg, "pad") == 0)
	{
		extern int pad_create(char*);
		sh_close(fdo);
		fdo = pad_create(fname);
		pad_wait(fdo);
		unlink(fname);
		strcat(fname, ".bak");
		unlink(fname);
		lseek(fdo,(off_t)0,SEEK_SET);
	}
	else
	{
#endif /* apollo */
	if(*arg != '-')
	{
		char *com[3];
		com[0] =  arg;
		com[1] =  fname;
		com[2] = 0;
		error_info.errors = sh_eval(sh_sfeval(com),0);
	}
	fdo = sh_chkopen(fname);
	unlink(fname);
	free((void*)fname);
#ifdef apollo
	}
#endif /* apollo */
	/* don't history fc itself unless forked */
	error_info.flags |= ERROR_SILENT;
	if(!sh_isstate(SH_FORKED))
		hist_cancel(hp);
	sh_onstate(SH_HISTORY);
	sh_onstate(SH_VERBOSE);	/* echo lines as read */
	if(replace)
		hist_subst(error_info.id,fdo,replace);
	else if(error_info.errors == 0)
	{
		char buff[IOBSIZE+1];
		Sfio_t *iop = sfnew(NIL(Sfio_t*),buff,IOBSIZE,fdo,SF_READ);
		/* read in and run the command */
		if(shp->hist_depth++ > HIST_RECURSE)
			errormsg(SH_DICT,ERROR_exit(1),e_toodeep,"history");
		sh_eval(iop,1);
		shp->hist_depth--;
	}