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

📄 hist.c

📁 早期freebsd实现
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * Copyright (c) 1994 David I. Bell * Permission is granted to use, distribute, or modify this source, * provided that this copyright notice remains intact. * * Adapted from code written by Stephen Rothwell. * * Interactive readline module.  This is called to read lines of input, * while using emacs-like editing commands within a command stack. * The key bindings for the editing commands are (slightly) configurable. */#include <stdio.h>#include <ctype.h>#include <pwd.h>#include "hist.h"#include "terminal.h"#include "have_string.h"#if defined(USE_TERMIOS)# include <termios.h># define TTYSTRUCT	struct	termios#else /* USE_SGTTY */# if defined(USE_TERMIO)#  include <termio.h>#  define TTYSTRUCT	struct	termio# else /* USE_TERMIO */   /* assume USE_SGTTY */#  include <sys/ioctl.h>#  define TTYSTRUCT	struct	sgttyb# endif /* USE_TERMIO */#endif /* USE_SGTTY */#ifdef HAVE_STRING_H# include <string.h>#endif#define	STDIN		0#define	SAVE_SIZE	256		/* size of save buffer */#define	MAX_KEYS	60		/* number of key bindings */#define CONTROL(x)		((char)(((int)(x)) & 0x1f))static	struct {	char	*prompt;	char	*buf;	char	*pos;	char	*end;	char	*mark;	int	bufsize;	int	linelen;	int	histcount;	int	curhist;} HS;typedef	void (*FUNCPTR)();typedef struct {	char	*name;	FUNCPTR	func;} FUNC;static void	flush_input(), start_of_line(), end_of_line();static void	forward_char(), backward_char(), forward_word();static void	backward_word(), delete_char(), forward_kill_char();static void	backward_kill_char(), forward_kill_word(), kill_line();static void	new_line(), save_line(), forward_history();static void	backward_history(), insert_char();static void	goto_line(), list_history(), refresh_line(), swap_chars();static void	set_mark(), yank(), save_region(), kill_region();static void	reverse_search(), quote_char(), uppercase_word();static void	lowercase_word(), ignore_char(), arrow_key(), quit_calc();static	FUNC	funcs[] ={	{"ignore-char",		ignore_char},	{"flush-input",		flush_input},	{"start-of-line",	start_of_line},	{"end-of-line",		end_of_line},	{"forward-char",	forward_char},	{"backward-char",	backward_char},	{"forward-word",	forward_word},	{"backward-word",	backward_word},	{"delete-char",		delete_char},	{"forward-kill-char",	forward_kill_char},	{"backward-kill-char",	backward_kill_char},	{"forward-kill-word",	forward_kill_word},	{"uppercase-word",	uppercase_word},	{"lowercase-word",	lowercase_word},	{"kill-line",		kill_line},	{"goto-line",		goto_line},	{"new-line",		new_line},	{"save-line",		save_line},	{"forward-history",	forward_history},	{"backward-history",	backward_history},	{"insert-char",		insert_char},	{"list-history",	list_history},	{"refresh-line",	refresh_line},	{"swap-chars",		swap_chars},	{"set-mark",		set_mark},	{"yank",		yank},	{"save-region",		save_region},	{"kill-region",		kill_region},	{"reverse-search",	reverse_search},	{"quote-char",		quote_char},	{"arrow-key",		arrow_key},	{"quit",		quit_calc},	{NULL, 			NULL}};typedef struct key_ent	KEY_ENT;typedef struct key_map	KEY_MAP;struct key_ent	{	FUNCPTR		func;	KEY_MAP		*next;};struct key_map {	char		*name;	KEY_ENT		default_ent;	KEY_ENT		*map[256];};static char	base_map_name[] = "base-map";static char	esc_map_name[] = "esc-map";static KEY_MAP	maps[] = {	{base_map_name},	{esc_map_name}};#define	INTROUND	(sizeof(int) - 1)#define	HISTLEN(hp)	((((hp)->len + INTROUND) & ~INTROUND) + sizeof(int))#define	HISTOFFSET(hp)	(((char *) (hp)) - histbuf)#define	FIRSTHIST	((HIST *) histbuf)#define	NEXTHIST(hp)	((HIST *) (((char *) (hp)) + HISTLEN(hp)))typedef struct {	int	len;		/* length of data */	char	data[1];	/* varying length data */} HIST;static	int		inited;static	int		canedit;static	int		histused;static	int		key_count;static	int		save_len;static	TTYSTRUCT	oldtty;static	KEY_MAP		*cur_map;static	KEY_MAP		*base_map;static	KEY_ENT		key_table[MAX_KEYS];static	char		histbuf[HIST_SIZE + 1];static	char		save_buffer[SAVE_SIZE];static	FUNCPTR	find_func();static	HIST	*get_event();static	HIST	*find_event();static	void	read_key();static	void	erasechar();static	void	newline();static	void	backspace();static	void	beep();static	void	echo_char();static	void	echo_string();static	void	savetext();static	void	memrcpy();static	int	read_bindings();static	int	in_word();/* * Read a line into the specified buffer.  The line ends in a newline, * and is NULL terminated.  Returns the number of characters read, or * zero on an end of file or error.  The prompt is printed before reading * the line. */inthist_getline(prompt, buf, len)	char	*prompt;	char	*buf;	int	len;{	if (!inited)		(void) hist_init((char *) NULL);	HS.prompt = prompt;	HS.bufsize = len - 2;	HS.buf = buf;	HS.pos = buf;	HS.end = buf;	HS.mark = NULL;	HS.linelen = -1;	fputs(prompt, stdout);	fflush(stdout);	if (!canedit) {		if (fgets(buf, len, stdin) == NULL)			return 0;		return strlen(buf);	}	while (HS.linelen < 0)		read_key();	return HS.linelen;}/* * Initialize the module by reading in the key bindings from the specified * filename, and then setting the terminal modes for noecho and cbreak mode. * If the supplied filename is NULL, then a default filename will be used. * Returns zero if successful, or a nonzero error code if unsuccessful. * If this routine fails, hist_getline, hist_saveline, and hist_term can * still be called but all fancy editing is disabled. */inthist_init(filename)	char	*filename;{	TTYSTRUCT	newtty;	if (inited)		return HIST_INITED;	inited = 1;	canedit = 0;	if (filename == NULL)		filename = HIST_BINDING_FILE;	if (read_bindings(filename))		return HIST_NOFILE;#ifdef	USE_SGTTY	if (ioctl(STDIN, TIOCGETP, &oldtty) < 0)		return HIST_NOTTY;	newtty = oldtty;	newtty.sg_flags &= ~ECHO;	newtty.sg_flags |= CBREAK;	if (ioctl(STDIN, TIOCSETP, &newtty) < 0)		return HIST_NOTTY;#endif#ifdef	USE_TERMIO	if (ioctl(STDIN, TCGETA, &oldtty) < 0)		return HIST_NOTTY;	newtty = oldtty;	newtty.c_lflag &= ~(ECHO | ECHOE | ECHOK);	newtty.c_iflag |= ISTRIP;	newtty.c_lflag &= ~ICANON;	newtty.c_cc[VMIN] = 1;	newtty.c_cc[VTIME] = 0;	if (ioctl(STDIN, TCSETAW, &newtty) < 0)		return HIST_NOTTY;#endif#ifdef	USE_TERMIOS	if (tcgetattr(STDIN, &oldtty) < 0)		return HIST_NOTTY;	newtty = oldtty;	newtty.c_lflag &= ~(ECHO | ECHOE | ECHOK);	newtty.c_iflag |= ISTRIP;	newtty.c_lflag &= ~ICANON;	newtty.c_cc[VMIN] = 1;	newtty.c_cc[VTIME] = 0;	if (tcsetattr(STDIN, TCSANOW, &newtty) < 0)		return HIST_NOTTY;#endif	canedit = 1;	return HIST_SUCCESS;}/* * Reset the terminal modes just before exiting. */voidhist_term(){	if (!inited || !canedit) {		inited = 0;		return;	}#ifdef	USE_SGTTY	(void) ioctl(STDIN, TIOCSETP, &oldtty);#endif#ifdef	USE_TERMIO	(void) ioctl(STDIN, TCSETAW, &oldtty);#endif#ifdef	USE_TERMIOS	(void) tcsetattr(STDIN, TCSANOW, &oldtty);#endif}static KEY_MAP *find_map(map)	char	*map;{	int	i;	for (i = 0; i < sizeof(maps) / sizeof(maps[0]); i++) {		if (strcmp(map, maps[i].name) == 0)			return &maps[i];	}	return NULL;}static voidunbind_key(map, key)	int key;	KEY_MAP		*map;{	map->map[key] = NULL;}static voidraw_bind_key(map, key, func, next_map)	int key;	KEY_MAP		*map;	FUNCPTR		func;	KEY_MAP		*next_map;{	if (map->map[key] == NULL) {		if (key_count >= MAX_KEYS)			return;		map->map[key] = &key_table[key_count++];	}	map->map[key]->func = func;	map->map[key]->next = next_map;}static KEY_MAP *do_map_line(line)	char	line[];{	char	*cp;	char	*map_name;	cp = line;	while (isspace(*cp))		cp++;	if (*cp == '\0')		return NULL;	map_name = cp;	while ((*cp != '\0') && !isspace(*cp))		cp++;	*cp = '\0';	return find_map(map_name);}static voiddo_bind_line(map, line)	KEY_MAP		*map;	char		line[];{	char		*cp;	char		key;	char		*func_name;	char		*next_name;	KEY_MAP		*next;	FUNCPTR		func;	if (map == NULL)		return;	cp = line;	key = *cp++;	if (*cp == '\0') {		unbind_key(map, key);		return;	}	if (key == '^') {		if (*cp == '?') {			key = 0177;			cp++;		} else			key = CONTROL(*cp++);	}	else if (key == '\\')		key = *cp++;	while (isspace(*cp))		cp++;	if (*cp == '\0') {		unbind_key(map, key);		return;	}	func_name = cp;	while ((*cp != '\0') && !isspace(*cp))		cp++;	if (*cp) {		*cp++ = '\0';		while (isspace(*cp))			cp++;	}	func = find_func(func_name);	if (func == NULL) {		fprintf(stderr, "Unknown function \"%s\"\n", func_name);		return;	}	if (*cp == '\0') {		next = map->default_ent.next;		if (next == NULL)			next = base_map;	} else {		next_name = cp;		while ((*cp != '\0') && !isspace(*cp))			cp++;		if (*cp) {			*cp++ = '\0';			while (isspace(*cp))				cp++;		}		next = find_map(next_name);		if (next == NULL)			return;	}	raw_bind_key(map, key, func, next);}static voiddo_default_line(map, line)	KEY_MAP		*map;	char		*line;{	char		*cp;	char		*func_name;	char		*next_name;	KEY_MAP		*next;	FUNCPTR		func;	if (map == NULL)		return;	cp = line;	while (isspace(*cp))		cp++;	if (*cp == '\0')		return;	func_name = cp;	while ((*cp != '\0') && !isspace(*cp))		cp++;	if (*cp != '\0')	{		*cp++ = '\0';		while (isspace(*cp))			cp++;	}	func = find_func(func_name);	if (func == NULL)		return;	if (*cp == '\0')		next = map;	else	{		next_name = cp;		while ((*cp != '\0') && !isspace(*cp))			cp++;		if (*cp != '\0')		{			*cp++ = '\0';			while (isspace(*cp))				cp++;		}		next = find_map(next_name);		if (next == NULL)			return;	}	map->default_ent.func = func;	map->default_ent.next = next;}/* * Read bindings from specified file. * Returns nonzero on error. */static intread_bindings(bindfile)	char	*bindfile;{	char	*cp;	KEY_MAP	*input_map;	FILE	*fp;	char	line[100];	base_map = find_map(base_map_name);	cur_map = base_map;	input_map = base_map;	fp = fopen(bindfile, "r");	if (fp == NULL)		return 1;	while (fgets(line, sizeof(line) - 1, fp)) {		cp = line;		while (isspace(*cp))			cp++;		if ((*cp == '\0') || (*cp == '#') || (*cp == '\n'))			continue;		if (cp[strlen(cp) - 1] == '\n')			cp[strlen(cp) - 1] = '\0';		if (memcmp(cp, "map", 3) == 0)			input_map = do_map_line(&cp[3]);		else if (memcmp(cp, "default", 7) == 0)			do_default_line(input_map, &cp[7]);		else			do_bind_line(input_map, cp);	}	fclose(fp);	return 0;}static voidread_key(){	KEY_ENT		*ent;	int		key;	fflush(stdout);	key = fgetc(stdin);	if (key == EOF) {		HS.linelen = 0;		HS.buf[0] = '\0';		return;	}	ent = cur_map->map[key];	if (ent == NULL)		ent = &cur_map->default_ent;	if (ent->next)		cur_map = ent->next;	if (ent->func)		(*ent->func)(key);	else		insert_char(key);}/* * Return the Nth history event, indexed from zero. * Earlier history events are lower in number. */static HIST *get_event(n)	int n;{	register HIST *	hp;	if ((n < 0) || (n >= HS.histcount))		return NULL;	hp = FIRSTHIST;	while (n-- > 0)		hp = NEXTHIST(hp);	return hp;}/* * Search the history list for the specified pattern. * Returns the found history, or NULL. */static HIST *find_event(pat, len)	int len;	char *	pat;{	register HIST *	hp;	for (hp = FIRSTHIST; hp->len; hp = NEXTHIST(hp)) {		if ((hp->len == len) && (memcmp(hp->data, pat, len) == 0))		    	return hp;	}	return NULL;}/* * Insert a line into the end of the history table. * If the line already appears in the table, then it is moved to the end. * If the table is full, then the earliest commands are deleted as necessary. * Warning: the incoming line cannot point into the history table. */voidhist_saveline(line, len)	int len;	char *	line;{	HIST *	hp;	HIST *	hp2;	int	left;	if ((len > 0) && (line[len - 1] == '\n'))		len--;	if (len <= 0)		return;	/*	 * See if the line is already present in the history table.	 * If so, and it is already at the end, then we are all done.	 * Otherwise delete it since we will reinsert it at the end.	 */	hp = find_event(line, len);	if (hp) {		hp2 = NEXTHIST(hp);		left = histused - HISTOFFSET(hp2);		if (left <= 0)			return;		histused -= HISTLEN(hp);		memcpy(hp, hp2, left + 1);		HS.histcount--;	}	/*	 * If there is not enough room left in the history buffer to add	 * the new command, then repeatedly delete the earliest command	 * as many times as necessary in order to make enough room.	 */	while ((histused + len) >= HIST_SIZE) {		hp = (HIST *) histbuf;		hp2 = NEXTHIST(hp);		left = histused - HISTOFFSET(hp2);		histused -= HISTLEN(hp);		memcpy(hp, hp2, left + 1);		HS.histcount--;	}	/*	 * Add the line to the end of the history table.	 */	hp = (HIST *) &histbuf[histused];	hp->len = len;	memcpy(hp->data, line, len);	histused += HISTLEN(hp);	histbuf[histused] = 0;	HS.curhist = ++HS.histcount;}/* * Find the function for a specified name. */static FUNCPTRfind_func(name)	char	*name;{	FUNC	*fp;	for (fp = funcs; fp->name; fp++) {		if (strcmp(fp->name, name) == 0)			return fp->func;	}	return NULL;}static voidarrow_key(){	switch (fgetc(stdin)) {		case 'A':			backward_history();

⌨️ 快捷键说明

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