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

📄 hist.c

📁 Calc Software Package for Number Calc
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * hist - interactive readline module * * Copyright (C) 1999-2006  David I. Bell * * Calc is open software; you can redistribute it and/or modify it under * the terms of the version 2.1 of the GNU Lesser General Public License * as published by the Free Software Foundation. * * Calc is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU Lesser General * Public License for more details. * * A copy of version 2.1 of the GNU Lesser General Public License is * distributed with calc under the filename COPYING-LGPL.  You should have * received a copy with calc; if not, write to Free Software Foundation, Inc. * 59 Temple Place, Suite 330, Boston, MA  02111-1307, USA. * * @(#) $Revision: 29.12 $ * @(#) $Id: hist.c,v 29.12 2006/06/02 09:57:12 chongo Exp $ * @(#) $Source: /usr/local/src/cmd/calc/RCS/hist.c,v $ * * Under source code control:	1993/05/02 20:09:19 * File existed as early as:	1993 * * Share and enjoy!  :-)	http://www.isthe.com/chongo/tech/comp/calc/ *//* * Adapted from code written by Stephen Rothwell. * * GNU readline support added by Martin Buck <mbuck@debian.org> * * 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>#if !defined(_WIN32)# include <pwd.h>#endif#include "have_unistd.h"#if defined(HAVE_UNISTD_H)#include <unistd.h>#endif#include "have_stdlib.h"#if defined(HAVE_STDLIB_H)#include <stdlib.h>#endif#include "calc.h"#include "hist.h"#include "have_string.h"#include "have_strdup.h"#if !defined(HAVE_STRDUP)# define strdup(x) calc_strdup((CONST char *)(x))#endif /* HAVE_STRDUP */#ifdef HAVE_STRING_H# include <string.h>#endif#include "have_unused.h"#if !defined(USE_READLINE)extern FILE *curstream(void);#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;	BOOL	virgin_line;	/* 1 => never typed chars, 0 => chars typed */} HS;typedef void (*FUNCPTR)();typedef struct {	char	*name;	FUNCPTR func;} FUNC;/* declare binding functions */static void flush_input(void);static void start_of_line(void);static void end_of_line(void);static void forward_char(void);static void backward_char(void);static void forward_word(void);static void backward_word(void);static void delete_char(void);static void forward_kill_char(void);static void backward_kill_char(void);static void forward_kill_word(void);static void kill_line(void);static void new_line(void);static void save_line(void);static void forward_history(void);static void backward_history(void);static void insert_char(int key);static void goto_line(void);static void list_history(void);static void refresh_line(void);static void swap_chars(void);static void set_mark(void);static void yank(void);static void save_region(void);static void kill_region(void);static void reverse_search(void);static void quote_char(void);static void uppercase_word(void);static void lowercase_word(void);static void ignore_char(void);static void arrow_key(void);static void quit_calc(void);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, {NULL, NULL}, {NULL, NULL}},	{esc_map_name, {NULL, NULL}, {NULL, NULL}},};#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	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];/* declare other static functions */static	FUNCPTR find_func(char *name);static	HIST	*get_event(int n);static	HIST	*find_event(char *pat, int len);static	void	read_key(void);static	void	erasechar(void);static	void	newline(void);static	void	backspace(void);static	void	beep(void);static	void	echo_char(int ch);static	void	echo_string(char *str, int len);static	void	savetext(char *str, int len);static	void	memrcpy(char *dest, char *src, int len);static	int	read_bindings(FILE *fp);static	int	in_word(int ch);static	KEY_MAP *find_map(char *map);static	void	unbind_key(KEY_MAP *map, int key);static	void	raw_bind_key(KEY_MAP *map, int key,			     FUNCPTR func, KEY_MAP *next_map);static	KEY_MAP *do_map_line(char *line);static	void	do_default_line(KEY_MAP *map, char *line);static	void	do_bind_line(KEY_MAP *map, char *line);static	void	back_over_char(int ch);static	void	echo_rest_of_line(void);static	void	goto_start_of_line(void);static	void	goto_end_of_line(void);static	void	remove_char(int ch);static	void	decrement_end(int n);static	void	insert_string(char *str, int len);/* * 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. */size_thist_getline(char *prompt, char *buf, size_t len){	/*	 * initialize if we have not already done so	 */	if (!inited)		(void) hist_init(calcbindings);	/*	 * establish the beginning of a line condition	 */	HS.prompt = prompt;	HS.bufsize = len - 2;	HS.buf = buf;	HS.pos = buf;	HS.end = buf;	HS.mark = NULL;	HS.linelen = -1;	HS.virgin_line = TRUE;	/*	 * prep the I/O	 */	fputs(prompt, stdout);	fflush(stdout);	/*	 * special case: non-interactive editing	 */	if (!canedit) {		if (fgets(buf, len, stdin) == NULL)			return 0;		return strlen(buf);	}	/*	 * get the line	 */	while (HS.linelen < 0) {		/* get the next char */		read_key();		/* chars typed, no longer virgin */		HS.virgin_line = FALSE;	}	/*	 * return the line	 */	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. * We will search the CALCPATH for the file. * * 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(char *filename){	/*	 * prevent multiple initializations	 */	if (inited) {		if (conf->calc_debug & CALCDBG_TTY)			printf("hist_init: inited already set\n");		return HIST_INITED;	}	/*	 * setup	 */	inited = 1;	canedit = 0;	if (conf->calc_debug & CALCDBG_TTY)		printf("hist_init: Set inited, cleared canedit\n");	/*	 * open the bindings file	 */	if (filename == NULL)		filename = HIST_BINDING_FILE;	if (opensearchfile(filename, calcpath, NULL, FALSE) > 0)		return HIST_NOFILE;	/*	 * load the bindings	 */	if (read_bindings(curstream()))		return HIST_NOFILE;	/*	 * close the bindings	 */	closeinput();	/*	 * setup the calc TTY on STDIN	 */	if (!calc_tty(STDIN)) {		return HIST_NOTTY;	}	canedit = 1;	if (conf->calc_debug & CALCDBG_TTY)		printf("hist_init: Set canedit\n");	return HIST_SUCCESS;}/* * Reset the terminal modes just before exiting. */voidhist_term(void){	if (!inited || !canedit) {		if (conf->calc_debug & CALCDBG_TTY) {			if (!inited)				printf("hist_term: inited already cleared\n");			if (!canedit)				printf("hist_term: canedit already cleared\n");		}		inited = 0;		if (conf->calc_debug & CALCDBG_TTY)			printf("hist_term: Cleared inited\n");		return;	}	/*	 * restore orignal tty state	 */	(void) orig_tty(STDIN);}static KEY_MAP *find_map(char *map){	unsigned 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(KEY_MAP *map, int key){	map->map[key] = NULL;}static voidraw_bind_key(KEY_MAP *map, int key, 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(char *line){	char	*cp;	char	*map_name;	cp = line;	while (isspace((int)*cp))		cp++;	if (*cp == '\0')		return NULL;	map_name = cp;	while ((*cp != '\0') && !isspace((int)*cp))		cp++;	*cp = '\0';	return find_map(map_name);}static voiddo_bind_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((int)*cp))		cp++;	if (*cp == '\0') {		unbind_key(map, key);		return;	}	func_name = cp;	while ((*cp != '\0') && !isspace((int)*cp))		cp++;	if (*cp) {		*cp++ = '\0';		while (isspace((int)*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((int)*cp))			cp++;		if (*cp) {			*cp++ = '\0';			while (isspace((int)*cp))				cp++;		}		next = find_map(next_name);		if (next == NULL)			return;	}	raw_bind_key(map, key, func, next);}static voiddo_default_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((int)*cp))		cp++;	if (*cp == '\0')		return;	func_name = cp;	while ((*cp != '\0') && !isspace((int)*cp))		cp++;	if (*cp != '\0') {		*cp++ = '\0';		while (isspace((int)*cp))			cp++;	}	func = find_func(func_name);	if (func == NULL)		return;	if (*cp == '\0') {		next = map;	} else {		next_name = cp;		while ((*cp != '\0') && !isspace((int)*cp))			cp++;		if (*cp != '\0') {			*cp++ = '\0';			while (isspace((int)*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 open file. * * Returns nonzero on error. */static intread_bindings(FILE *fp){	char	*cp;	KEY_MAP *input_map;	char	line[BUFSIZ+1];	base_map = find_map(base_map_name);	cur_map = base_map;	input_map = base_map;	if (fp == NULL)		return 1;	while (fgets(line, sizeof(line) - 1, fp)) {		line[BUFSIZ] = '\0';		cp = line;		while (isspace((int)*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);	}	return 0;}static voidread_key(void){	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)		/* ignore Saber-C warning #65 - has 1 arg, expecting 0 */		/*	  ok to ignore in proc read_key */		(*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(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(char *pat, int len){	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(char *line, int len){	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(char *name){	FUNC	*fp;	for (fp = funcs; fp->name; fp++) {		if (strcmp(fp->name, name) == 0)			return fp->func;	}	return NULL;}static voidarrow_key(void){	switch (fgetc(stdin)) {	case 'A':		backward_history();		break;	case 'B':		forward_history();		break;	case 'C':		forward_char();		break;	case 'D':		backward_char();		break;	}}static voidback_over_char(int ch){	backspace();	if (!isprint(ch))		backspace();}static void

⌨️ 快捷键说明

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