⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 history.c

📁 这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易于我们学习和理解
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * command history * * only implements in-memory history. *//* *	This file contains *	a)	the original in-memory history  mechanism *	b)	a simple file saving history mechanism done by  sjg@zen *		define EASY_HISTORY to get this *	c)	a more complicated mechanism done by  pc@hillside.co.uk *		that more closely follows the real ksh way of doing *		things. You need to have the mmap system call for this *		to work on your system */#include "sh.h"#include "ksh_stat.h"#ifdef HISTORY# ifdef EASY_HISTORY#  ifndef HISTFILE#   ifdef OS2#    define HISTFILE "history.ksh"#   else /* OS2 */#    define HISTFILE ".pdksh_history"#   endif /* OS2 */#  endif# else/*	Defines and includes for the complicated case */#  include <sys/file.h>#  include <sys/mman.h>/* *	variables for handling the data file */static int	histfd;static int	hsize;static int hist_count_lines ARGS((unsigned char *, int));static int hist_shrink ARGS((unsigned char *, int));static unsigned char *hist_skip_back ARGS((unsigned char *,int *,int));static void histload ARGS((Source *, unsigned char *, int));static void histinsert ARGS((Source *, int, unsigned char *));static void writehistfile ARGS((int, char *));static int sprinkle ARGS((int));#  ifdef MAP_FILE#   define MAP_FLAGS	(MAP_FILE|MAP_PRIVATE)#  else#   define MAP_FLAGS	MAP_PRIVATE#  endif# endif	/* of EASY_HISTORY */static int	hist_execute ARGS((char *cmd));static int	hist_replace ARGS((char **hp, const char *pat, const char *rep,				   int global));static char   **hist_get ARGS((const char *str, int approx, int allow_cur));static char   **hist_get_newest ARGS((int allow_cur));static char   **hist_get_oldest ARGS(());static void	histbackup ARGS((void));static char   **current;	/* current postition in history[] */static int	curpos;		/* current index in history[] */static char    *hname;		/* current name of history file */static int	hstarted;	/* set after hist_init() called */static Source	*hist_source;intc_fc(wp)	char **wp;{	struct shf *shf;	struct temp UNINITIALIZED(*tf);	char *p, *editor = (char *) 0;	int gflag = 0, lflag = 0, nflag = 0, sflag = 0, rflag = 0;	int optc;	char *first = (char *) 0, *last = (char *) 0;	char **hfirst, **hlast, **hp;	while ((optc = ksh_getopt(wp, &builtin_opt, "e:glnrs0,1,2,3,4,5,6,7,8,9,")) != EOF)		switch (optc) {		  case 'e':			p = builtin_opt.optarg;			if (strcmp(p, "-") == 0)				sflag++;			else {				editor = str_nsave(p, strlen(p) + 4, ATEMP);				strcat(editor, " $_");			}			break;		  case 'g': /* non-at&t ksh */			gflag++;			break;		  case 'l':			lflag++;			break;		  case 'n':			nflag++;			break;		  case 'r':			rflag++;			break;		  case 's':	/* posix version of -e - */			sflag++;			break;		  /* kludge city - accept -num as -- -num (kind of) */		  case '0': case '1': case '2': case '3': case '4':		  case '5': case '6': case '7': case '8': case '9':			p = shf_smprintf("-%c%s",					optc, builtin_opt.optarg);			if (!first)				first = p;			else if (!last)				last = p;			else {				bi_errorf("too many arguments");				return 1;			}			break;		  case '?':			return 1;		}	wp += builtin_opt.optind;	/* Substitute and execute command */	if (sflag) {		char *pat = (char *) 0, *rep = (char *) 0;		if (editor || lflag || nflag || rflag) {			bi_errorf("can't use -e, -l, -n, -r with -s (-e -)");			return 1;		}		/* Check for pattern replacement argument */		if (*wp && **wp && (p = strchr(*wp + 1, '='))) {			pat = str_save(*wp, ATEMP);			p = pat + (p - *wp);			*p++ = '\0';			rep = p;			wp++;		}		/* Check for search prefix */		if (!first && (first = *wp))			wp++;		if (last || *wp) {			bi_errorf("too many arguments");			return 1;		}		hp = first ? hist_get(first, FALSE, FALSE)			   : hist_get_newest(FALSE);		if (!hp)			return 1;		return hist_replace(hp, pat, rep, gflag);	}	if (editor && (lflag || nflag)) {		bi_errorf("can't use -l, -n with -e");		return 1;	}	if (!first && (first = *wp))		wp++;	if (!last && (last = *wp))		wp++;	if (*wp) {		bi_errorf("too many arguments");		return 1;	}	if (!first) {		hfirst = lflag ? hist_get("-16", TRUE, TRUE)			       : hist_get_newest(FALSE);		if (!hfirst)			return 1;		/* can't fail if hfirst didn't fail */		hlast = hist_get_newest(FALSE);	} else {		/* POSIX says not an error if first/last out of bounds		 * when range is specified; at&t ksh and pdksh allow out of		 * bounds for -l as well.		 */		hfirst = hist_get(first, (lflag || last) ? TRUE : FALSE,				lflag ? TRUE : FALSE);		if (!hfirst)			return 1;		hlast = last ? hist_get(last, TRUE, lflag ? TRUE : FALSE)			    : (lflag ? hist_get_newest(FALSE) : hfirst);		if (!hlast)			return 1;	}	if (hfirst > hlast) {		char **temp;		temp = hfirst; hfirst = hlast; hlast = temp;		rflag = !rflag; /* POSIX */	}	/* List history */	if (lflag) {		char *s, *t;		const char *nfmt = nflag ? "\t" : "%d\t";		for (hp = rflag ? hlast : hfirst;		     hp >= hfirst && hp <= hlast; hp += rflag ? -1 : 1)		{			shf_fprintf(shl_stdout, nfmt,				hist_source->line - (int) (histptr - hp));			/* print multi-line commands correctly */			for (s = *hp; (t = strchr(s, '\n')); s = t)				shf_fprintf(shl_stdout, "%.*s\t", ++t - s, s);			shf_fprintf(shl_stdout, "%s\n", s);		}		shf_flush(shl_stdout);		return 0;	}	/* Run editor on selected lines, then run resulting commands */	tf = maketemp(ATEMP, TT_HIST_EDIT, &e->temps);	if (!(shf = tf->shf)) {		bi_errorf("cannot create temp file %s - %s",			tf->name, strerror(errno));		return 1;	}	for (hp = rflag ? hlast : hfirst;	     hp >= hfirst && hp <= hlast; hp += rflag ? -1 : 1)		shf_fprintf(shf, "%s\n", *hp);	if (shf_close(shf) == EOF) {		bi_errorf("error writing temporary file - %s", strerror(errno));		return 1;	}	/* Ignore setstr errors here (arbitrary) */	setstr(local("_", FALSE), tf->name, KSH_RETURN_ERROR);	/* XXX: source should not get trashed by this.. */	{		Source *sold = source;		int ret;		ret = command(editor ? editor : "${FCEDIT:-/bin/ed} $_");		source = sold;		if (ret)			return ret;	}	{		struct stat statb;		XString xs;		char *xp;		int n;		if (!(shf = shf_open(tf->name, O_RDONLY, 0, 0))) {			bi_errorf("cannot open temp file %s", tf->name);			return 1;		}		n = fstat(shf_fileno(shf), &statb) < 0 ? 128			: statb.st_size + 1;		Xinit(xs, xp, n, hist_source->areap);		while ((n = shf_read(xp, Xnleft(xs, xp), shf)) > 0) {			xp += n;			if (Xnleft(xs, xp) <= 0)				XcheckN(xs, xp, Xlength(xs, xp));		}		if (n < 0) {			bi_errorf("error reading temp file %s - %s",				tf->name, strerror(shf_errno(shf)));			shf_close(shf);			return 1;		}		shf_close(shf);		*xp = '\0';		strip_nuls(Xstring(xs, xp), Xlength(xs, xp));		return hist_execute(Xstring(xs, xp));	}}/* Save cmd in history, execute cmd (cmd gets trashed) */static inthist_execute(cmd)	char *cmd;{	Source *sold;	int ret;	char *p, *q;	histbackup();	for (p = cmd; p; p = q) {		if ((q = strchr(p, '\n'))) {			*q++ = '\0'; /* kill the newline */			if (!*q) /* ignore trailing newline */				q = (char *) 0;		}#ifdef EASY_HISTORY		if (p != cmd)			histappend(p, TRUE);		else#endif /* EASY_HISTORY */			histsave(++(hist_source->line), p, 1);		shellf("%s\n", p); /* POSIX doesn't say this is done... */		if ((p = q)) /* restore \n (trailing \n not restored) */			q[-1] = '\n';	}	/* Commands are executed here instead of pushing them onto the	 * input 'cause posix says the redirection and variable assignments	 * in	 *	X=y fc -e - 42 2> /dev/null	 * are to effect the repeated commands environment.	 */	/* XXX: source should not get trashed by this.. */	sold = source;	ret = command(cmd);	source = sold;	return ret;}static inthist_replace(hp, pat, rep, global)	char **hp;	const char *pat;	const char *rep;	int global;{	char *line;	if (!pat)		line = str_save(*hp, ATEMP);	else {		char *s, *s1;		int pat_len = strlen(pat);		int rep_len = strlen(rep);		int len;		XString xs;		char *xp;		int any_subst = 0;		Xinit(xs, xp, 128, ATEMP);		for (s = *hp; (s1 = strstr(s, pat))			      && (!any_subst || global) ; s = s1 + pat_len)		{			any_subst = 1;			len = s1 - s;			XcheckN(xs, xp, len + rep_len);			memcpy(xp, s, len);		/* first part */			xp += len;			memcpy(xp, rep, rep_len);	/* replacement */			xp += rep_len;		}		if (!any_subst) {			bi_errorf("substitution failed");			return 1;		}		len = strlen(s) + 1;		XcheckN(xs, xp, len);		memcpy(xp, s, len);		xp += len;		line = Xclose(xs, xp);	}	return hist_execute(line);}/* * get pointer to history given pattern * pattern is a number or string */static char **hist_get(str, approx, allow_cur)	const char *str;	int approx;	int allow_cur;{	char **hp = (char **) 0;	int n;	if (getn(str, &n)) {		hp = histptr + (n < 0 ? n : (n - hist_source->line));		if (hp < history) {			if (approx)				hp = hist_get_oldest();			else {				bi_errorf("%s: not in history", str);				hp = (char **) 0;			}		} else if (hp > histptr) {			if (approx)				hp = hist_get_newest(allow_cur);			else {				bi_errorf("%s: not in history", str);				hp = (char **) 0;			}		} else if (!allow_cur && hp == histptr) {			bi_errorf("%s: invalid range", str);			hp = (char **) 0;		}	} else {		int anchored = *str == '?' ? (++str, 0) : 1;		/* the -1 is to avoid the current fc command */		n = findhist(histptr - history - 1, 0, str, anchored);		if (n < 0) {			bi_errorf("%s: not in history", str);			hp = (char **) 0;		} else			hp = &history[n];	}	return hp;}/* Return a pointer to the newest command in the history */static char **hist_get_newest(allow_cur)	int allow_cur;{	if (histptr < history || (!allow_cur && histptr == history)) {		bi_errorf("no history (yet)");		return (char **) 0;	}	if (allow_cur)		return histptr;	return histptr - 1;}/* Return a pointer to the newest command in the history */static char **hist_get_oldest(){	if (histptr <= history) {		bi_errorf("no history (yet)");		return (char **) 0;	}	return history;}/******************************//* Back up over last histsave *//******************************/static voidhistbackup(){	static int last_line = -1;	if (histptr >= history && last_line != hist_source->line) {		hist_source->line--;		afree((void*)*histptr, APERM);		histptr--;		last_line = hist_source->line;	}}/* * Return the current position. */char **histpos(){	return current;}inthistN(){	return curpos;}inthistnum(n)	int	n;{	int	last = histptr - history;	if (n < 0 || n >= last) {		current = histptr;		curpos = last;		return last;	} else {		current = &history[n];		curpos = n;		return n;	}}/* * This will become unecessary if hist_get is modified to allow * searching from positions other than the end, and in either * direction. */intfindhist(start, fwd, str, anchored)	int	start;	int	fwd;	const char  *str;	int	anchored;{	char	**hp;	int	maxhist = histptr - history;	int	incr = fwd ? 1 : -1;	int	len = strlen(str);	if (start < 0 || start >= maxhist)		start = maxhist;	hp = &history[start];	for (; hp >= history && hp <= histptr; hp += incr)		if ((anchored && strncmp(*hp, str, len) == 0)		    || (!anchored && strstr(*hp, str)))			return hp - history;	return -1;}/* *	set history *	this means reallocating the dataspace */voidsethistsize(n)	int n;{	if (n > 0 && n != histsize) {		int cursize = histptr - history;		/* save most recent history */		if (n < cursize) {			memmove(history, histptr - n, n * sizeof(char *));			cursize = n;		}		history = (char **)aresize(history, n*sizeof(char *), APERM);		histsize = n;		histptr = history + cursize;	}}/* *	set history file *	This can mean reloading/resetting/starting history file *	maintenance */voidsethistfile(name)	const char *name;{	/* if not started then nothing to do */	if (hstarted == 0)		return;	/* if the name is the same as the name we have */	if (hname && strcmp(hname, name) == 0)		return;	/*	 * its a new name - possibly	 */# ifdef EASY_HISTORY	if (hname) {		afree(hname, APERM);		hname = NULL;	}# else	if (histfd) {		/* yes the file is open */		(void) close(histfd);		histfd = 0;		hsize = 0;		afree(hname, APERM);		hname = NULL;		/* let's reset the history */		histptr = history - 1;		hist_source->line = 0;	}# endif	hist_init(hist_source);}/* *	initialise the history vector */voidinit_histvec(){	if (history == (char **)NULL) {		histsize = HISTORYSIZE;		history = (char **)alloc(histsize*sizeof (char *), APERM);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -