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

📄 history.c

📁 这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易于我们学习和理解
💻 C
📖 第 1 页 / 共 2 页
字号:
		histptr = history - 1;	}}# ifdef EASY_HISTORY/* * save command in history */voidhistsave(lno, cmd, dowrite)	int lno;	/* ignored (compatibility with COMPLEX_HISTORY) */	const char *cmd;	int dowrite;	/* ignored (compatibility with COMPLEX_HISTORY) */{	register char **hp = histptr;	char *cp;	if (++hp >= history + histsize) { /* remove oldest command */		afree((void*)history[0], APERM);		memmove(history, history + 1,			sizeof(history[0]) * (histsize - 1));		hp = &history[histsize - 1];	}	*hp = str_save(cmd, APERM);	/* trash trailing newline but allow imbedded newlines */	cp = *hp + strlen(*hp);	if (cp > *hp && cp[-1] == '\n')		cp[-1] = '\0';	histptr = hp;}/* * Append an entry to the last saved command. Used for multiline * commands */voidhistappend(cmd, nl_separate)	const char *cmd;	int	nl_separate;{	int	hlen, clen;	char	*p;	hlen = strlen(*histptr);	clen = strlen(cmd);	if (clen > 0 && cmd[clen-1] == '\n')		clen--;	p = *histptr = (char *) aresize(*histptr, hlen + clen + 2, APERM);	p += hlen;	if (nl_separate)		*p++ = '\n';	memcpy(p, cmd, clen);	p[clen] = '\0';}/* * 92-04-25 <sjg@zen> * A simple history file implementation. * At present we only save the history when we exit. * This can cause problems when there are multiple shells are * running under the same user-id.  The last shell to exit gets * to save its history. */voidhist_init(s)	Source *s;{	char *f;	FILE *fh;	if (Flag(FTALKING) == 0)		return;	hstarted = 1;	hist_source = s;	if ((f = str_val(global("HISTFILE"))) == NULL || *f == '\0') {# if 1 /* Don't use history file unless the user asks for it */		hname = NULL;		return;# else		char *home = str_val(global("HOME"));		int len;		if (home == NULL)			home = null;		f = HISTFILE;		hname = alloc(len = strlen(home) + strlen(f) + 2, APERM);		shf_snprintf(hname, len, "%s/%s", home, f);# endif	} else		hname = str_save(f, APERM);	if ((fh = fopen(hname, "r"))) {		int pos = 0, nread = 0;		int contin = 0;		/* continuation of previous command */		char *end;		char hline[LINE + 1];		while (1) {			if (pos >= nread) {				pos = 0;				nread = fread(hline, 1, LINE, fh);				if (nread <= 0)					break;				hline[nread] = '\0';			}			end = strchr(hline + pos, 0); /* will always succeed */			if (contin)				histappend(hline + pos, 0);			else {				hist_source->line++;				histsave(0, hline + pos, 0);			}			pos = end - hline + 1;			contin = end == &hline[nread];		}		fclose(fh);	}}/* * save our history. * We check that we do not have more than we are allowed. * If the history file is read-only we do nothing. * Handy for having all shells start with a useful history set. */voidhist_finish(){  static int once;  FILE *fh;  register int i;  register char **hp;  if (once++)    return;  /* check how many we have */  i = histptr - history;  if (i >= histsize)    hp = &histptr[-histsize];  else    hp = history;  if (hname && (fh = fopen(hname, "w")))  {    for (i = 0; hp + i <= histptr && hp[i]; i++)      fprintf(fh, "%s%c", hp[i], '\0');    fclose(fh);  }}# else /* EASY_HISTORY *//* *	Routines added by Peter Collinson BSDI(Europe)/Hillside Systems to *	a) permit HISTSIZE to control number of lines of history stored *	b) maintain a physical history file * *	It turns out that there is a lot of ghastly hackery here *//* * save command in history */voidhistsave(lno, cmd, dowrite)	int lno;	const char *cmd;	int dowrite;{	register char **hp;	char *c, *cp;	c = str_save(cmd, APERM);	if ((cp = strchr(c, '\n')) != NULL)		*cp = '\0';	if (histfd && dowrite)		writehistfile(lno, c);	hp = histptr;	if (++hp >= history + histsize) { /* remove oldest command */		afree((void*)*history, APERM);		for (hp = history; hp < history + histsize - 1; hp++)			hp[0] = hp[1];	}	*hp = c;	histptr = hp;}/* *	Write history data to a file nominated by HISTFILE *	if HISTFILE is unset then history still happens, but *	the data is not written to a file *	All copies of ksh looking at the file will maintain the *	same history. This is ksh behaviour. * *	This stuff uses mmap() *	if your system ain't got it - then you'll have to undef HISTORYFILE *//* *	Open a history file *	Format is: *	Bytes 1, 2: HMAGIC - just to check that we are dealing with *		    the correct object *	Then follows a number of stored commands *	Each command is *	<command byte><command number(4 bytes)><bytes><null> */# define HMAGIC1		0xab# define HMAGIC2		0xcd# define COMMAND		0xffvoidhist_init(s)	Source *s;{	unsigned char	*base;	int	lines;	int	fd;	if (Flag(FTALKING) == 0)		return;	hstarted = 1;	hist_source = s;	hname = str_val(global("HISTFILE"));	if (hname == NULL)		return;	hname = str_save(hname, APERM);  retry:	/* we have a file and are interactive */	if ((fd = open(hname, O_RDWR|O_CREAT|O_APPEND, 0600)) < 0)		return;	histfd = savefd(fd, 0);	(void) flock(histfd, LOCK_EX);	hsize = lseek(histfd, 0L, SEEK_END);	if (hsize == 0) {		/* add magic */		if (sprinkle(histfd)) {			hist_finish();			return;		}	}	else if (hsize > 0) {		/*		 * we have some data		 */		base = (unsigned char *)mmap(0, hsize, PROT_READ, MAP_FLAGS, histfd, 0);		/*		 * check on its validity		 */		if ((int)base == -1 || *base != HMAGIC1 || base[1] != HMAGIC2) {			if ((int)base !=  -1)				munmap((caddr_t)base, hsize);			hist_finish();			unlink(hname);			goto retry;		}		if (hsize > 2) {			lines = hist_count_lines(base+2, hsize-2);			if (lines > histsize) {				/* we need to make the file smaller */				if (hist_shrink(base, hsize))					unlink(hname);				munmap((caddr_t)base, hsize);				hist_finish();				goto retry;			}		}		histload(hist_source, base+2, hsize-2);		munmap((caddr_t)base, hsize);	}	(void) flock(histfd, LOCK_UN);	hsize = lseek(histfd, 0L, SEEK_END);}typedef enum state {	shdr,		/* expecting a header */	sline,		/* looking for a null byte to end the line */	sn1,		/* bytes 1 to 4 of a line no */	sn2, sn3, sn4,} State;static inthist_count_lines(base, bytes)	register unsigned char *base;	register int bytes;{	State state = shdr;	register lines = 0;	while (bytes--) {		switch (state)		{		case shdr:			if (*base == COMMAND)				state = sn1;			break;		case sn1:			state = sn2; break;		case sn2:			state = sn3; break;		case sn3:			state = sn4; break;		case sn4:			state = sline; break;		case sline:			if (*base == '\0')				lines++, state = shdr;		}		base++;	}	return lines;}/* *	Shrink the history file to histsize lines */static inthist_shrink(oldbase, oldbytes)	unsigned char *oldbase;	int oldbytes;{	int fd;	char	nfile[1024];	struct	stat statb;	unsigned char *nbase = oldbase;	int nbytes = oldbytes;	nbase = hist_skip_back(nbase, &nbytes, histsize);	if (nbase == NULL)		return 1;	if (nbase == oldbase)		return 0;	/*	 *	create temp file	 */	(void) shf_snprintf(nfile, sizeof(nfile), "%s.%d", hname, procpid);	if ((fd = creat(nfile, 0600)) < 0)		return 1;	if (sprinkle(fd)) {		close(fd);		unlink(nfile);		return 1;	}	if (write(fd, nbase, nbytes) != nbytes) {		close(fd);		unlink(nfile);		return 1;	}	/*	 *	worry about who owns this file	 */	if (fstat(histfd, &statb) >= 0)		fchown(fd, statb.st_uid, statb.st_gid);	close(fd);	/*	 *	rename	 */	if (rename(nfile, hname) < 0)		return 1;	return 0;}/* *	find a pointer to the data `no' back from the end of the file *	return the pointer and the number of bytes left */static unsigned char *hist_skip_back(base, bytes, no)	unsigned char *base;	int *bytes;	int no;{	register int lines = 0;	register unsigned char *ep;	for (ep = base + *bytes; --ep > base; ) {		/* this doesn't really work: the 4 byte line number that is		 * encoded after the COMMAND byte can itself contain the		 * COMMAND byte....		 */		for (; ep > base && *ep != COMMAND; ep--)			;		if (ep == base)			break;		if (++lines == no) {			*bytes = *bytes - ((char *)ep - (char *)base);			return ep;		}	}	return NULL;}/* *	load the history structure from the stored data */static voidhistload(s, base, bytes)	Source *s;	register unsigned char *base;	register int bytes;{	State state;	int	lno;	unsigned char	*line;	for (state = shdr; bytes-- > 0; base++) {		switch (state) {		case shdr:			if (*base == COMMAND)				state = sn1;			break;		case sn1:			lno = (((*base)&0xff)<<24);			state = sn2;			break;		case sn2:			lno |= (((*base)&0xff)<<16);			state = sn3;			break;		case sn3:			lno |= (((*base)&0xff)<<8);			state = sn4;			break;		case sn4:			lno |= (*base)&0xff;			line = base+1;			state = sline;			break;		case sline:			if (*base == '\0') {				/* worry about line numbers */				if (histptr >= history && lno-1 != s->line) {					/* a replacement ? */					histinsert(s, lno, line);				}				else {					s->line = lno;					histsave(lno, (char *)line, 0);				}				state = shdr;			}		}	}}/* *	Insert a line into the history at a specified number */static voidhistinsert(s, lno, line)	Source *s;	int lno;	unsigned char *line;{	register char **hp;	if (lno >= s->line-(histptr-history) && lno <= s->line) {		hp = &histptr[lno-s->line];		if (*hp)			afree((void*)*hp, APERM);		*hp = str_save((char *)line, APERM);	}}/* *	write a command to the end of the history file *	This *MAY* seem easy but it's also necessary to check *	that the history file has not changed in size. *	If it has - then some other shell has written to it *	and we should read those commands to update our history */static voidwritehistfile(lno, cmd)	int lno;	char *cmd;{	int	sizenow;	unsigned char	*base;	unsigned char	*new;	int	bytes;	char	hdr[5];	(void) flock(histfd, LOCK_EX);	sizenow = lseek(histfd, 0L, SEEK_END);	if (sizenow != hsize) {		/*		 *	Things have changed		 */		if (sizenow > hsize) {			/* someone has added some lines */			bytes = sizenow - hsize;			base = (unsigned char *)mmap(0, sizenow, PROT_READ, MAP_FLAGS, histfd, 0);			if ((int)base == -1)				goto bad;			new = base + hsize;			if (*new != COMMAND) {				munmap((caddr_t)base, sizenow);				goto bad;			}			hist_source->line--;			histload(hist_source, new, bytes);			hist_source->line++;			lno = hist_source->line;			munmap((caddr_t)base, sizenow);			hsize = sizenow;		} else {			/* it has shrunk */			/* but to what? */			/* we'll give up for now */			goto bad;		}	}	/*	 *	we can write our bit now	 */	hdr[0] = COMMAND;	hdr[1] = (lno>>24)&0xff;	hdr[2] = (lno>>16)&0xff;	hdr[3] = (lno>>8)&0xff;	hdr[4] = lno&0xff;	(void) write(histfd, hdr, 5);	(void) write(histfd, cmd, strlen(cmd)+1);	hsize = lseek(histfd, 0L, SEEK_END);	(void) flock(histfd, LOCK_UN);	return;bad:	hist_finish();}voidhist_finish(){	(void) flock(histfd, LOCK_UN);	(void) close(histfd);	histfd = 0;}/* *	add magic to the history file */static intsprinkle(fd)	int fd;{	static char mag[] = { HMAGIC1, HMAGIC2 };	return(write(fd, mag, 2) != 2);}# endif#else /* HISTORY *//* No history to be compiled in: dummy routines to avoid lots more ifdefs */voidinit_histvec(){}voidhist_init(s)	Source *s;{}voidhist_finish(){}voidhistsave(lno, cmd, dowrite)	int lno;	const char *cmd;	int dowrite;{	errorf("history not enabled");}#endif /* HISTORY */

⌨️ 快捷键说明

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