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

📄 cmdedit.c

📁 shell-HHARM9200.rar 华恒 AT91rm9200 中Busybox shell的源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* vi: set sw=4 ts=4: *//* * Termios command line History and Editting. * * Copyright (c) 1986-2003 may safely be consumed by a BSD or GPL license. * Written by:   Vladimir Oleynik <dzo@simtreas.ru> * * Used ideas: *      Adam Rogoyski    <rogoyski@cs.utexas.edu> *      Dave Cinege      <dcinege@psychosis.com> *      Jakub Jelinek (c) 1995 *      Erik Andersen    <andersen@codepoet.org> (Majorly adjusted for busybox) * * This code is 'as is' with no warranty. * * *//*   Usage and Known bugs:   Terminal key codes are not extensive, and more will probably   need to be added. This version was created on Debian GNU/Linux 2.x.   Delete, Backspace, Home, End, and the arrow keys were tested   to work in an Xterm and console. Ctrl-A also works as Home.   Ctrl-E also works as End.   Small bugs (simple effect):   - not true viewing if terminal size (x*y symbols) less     size (prompt + editor`s line + 2 symbols)   - not true viewing if length prompt less terminal width */#include <stdio.h>#include <errno.h>#include <unistd.h>#include <stdlib.h>#include <string.h>#include <sys/ioctl.h>#include <ctype.h>#include <signal.h>#include <limits.h>#include "busybox.h"#include "../shell/cmdedit.h"#ifdef CONFIG_LOCALE_SUPPORT#define Isprint(c) isprint((c))#else#define Isprint(c) ( (c) >= ' ' && (c) != ((unsigned char)'\233') )#endif#ifdef TEST/* pretect redefined for test */#undef CONFIG_FEATURE_COMMAND_EDITING#undef CONFIG_FEATURE_COMMAND_TAB_COMPLETION#undef CONFIG_FEATURE_COMMAND_USERNAME_COMPLETION#undef CONFIG_FEATURE_NONPRINTABLE_INVERSE_PUT#undef CONFIG_FEATURE_CLEAN_UP#define CONFIG_FEATURE_COMMAND_EDITING#define CONFIG_FEATURE_COMMAND_TAB_COMPLETION#define CONFIG_FEATURE_COMMAND_USERNAME_COMPLETION#define CONFIG_FEATURE_NONPRINTABLE_INVERSE_PUT#define CONFIG_FEATURE_CLEAN_UP#endif                                                  /* TEST */#ifdef CONFIG_FEATURE_COMMAND_TAB_COMPLETION#include <dirent.h>#include <sys/stat.h>#endif#ifdef CONFIG_FEATURE_COMMAND_EDITING#if defined(CONFIG_FEATURE_COMMAND_USERNAME_COMPLETION) || defined(CONFIG_FEATURE_SH_FANCY_PROMPT)#define CONFIG_FEATURE_GETUSERNAME_AND_HOMEDIR#endif#ifdef CONFIG_FEATURE_GETUSERNAME_AND_HOMEDIR#include "pwd_.h"#endif                                                  /* advanced FEATURES *//* Maximum length of the linked list for the command line history */#ifndef CONFIG_FEATURE_COMMAND_HISTORY#define MAX_HISTORY   15#else#define MAX_HISTORY   CONFIG_FEATURE_COMMAND_HISTORY#endif#if MAX_HISTORY < 1#warning cmdedit: You set MAX_HISTORY < 1. The history algorithm switched off.#elsestatic char *history[MAX_HISTORY+1]; /* history + current *//* saved history lines */static int n_history;/* current pointer to history line */static int cur_history;#endif#include <termios.h>#define setTermSettings(fd,argp) tcsetattr(fd,TCSANOW,argp)#define getTermSettings(fd,argp) tcgetattr(fd, argp);/* Current termio and the previous termio before starting sh */static struct termios initial_settings, new_settings;staticvolatile int cmdedit_termw = 80;        /* actual terminal width */staticvolatile int handlers_sets = 0; /* Set next bites: */enum {	SET_ATEXIT = 1,         /* when atexit() has been called				   and get euid,uid,gid to fast compare */	SET_WCHG_HANDLERS = 2,  /* winchg signal handler */	SET_RESET_TERM = 4,     /* if the terminal needs to be reset upon exit */};static int cmdedit_x;           /* real x terminal position */static int cmdedit_y;           /* pseudoreal y terminal position */static int cmdedit_prmt_len;    /* lenght prompt without colores string */static int cursor;              /* required global for signal handler */static int len;                 /* --- "" - - "" - -"- --""-- --""--- */static char *command_ps;        /* --- "" - - "" - -"- --""-- --""--- */static#ifndef CONFIG_FEATURE_SH_FANCY_PROMPT	const#endifchar *cmdedit_prompt;           /* --- "" - - "" - -"- --""-- --""--- */#ifdef CONFIG_FEATURE_GETUSERNAME_AND_HOMEDIRstatic char *user_buf = "";static char *home_pwd_buf = "";static int my_euid;#endif#ifdef CONFIG_FEATURE_SH_FANCY_PROMPTstatic char *hostname_buf;static int num_ok_lines = 1;#endif#ifdef  CONFIG_FEATURE_COMMAND_TAB_COMPLETION#ifndef CONFIG_FEATURE_GETUSERNAME_AND_HOMEDIRstatic int my_euid;#endifstatic int my_uid;static int my_gid;#endif  /* CONFIG_FEATURE_COMMAND_TAB_COMPLETION */static void cmdedit_setwidth(int w, int redraw_flg);static void win_changed(int nsig){	static sighandler_t previous_SIGWINCH_handler;  /* for reset */	/*   emulate      || signal call */	if (nsig == -SIGWINCH || nsig == SIGWINCH) {		int width = 0;		get_terminal_width_height(0, &width, NULL);		cmdedit_setwidth(width, nsig == SIGWINCH);	}	/* Unix not all standart in recall signal */	if (nsig == -SIGWINCH)          /* save previous handler   */		previous_SIGWINCH_handler = signal(SIGWINCH, win_changed);	else if (nsig == SIGWINCH)      /* signaled called handler */		signal(SIGWINCH, win_changed);  /* set for next call       */	else                                            /* nsig == 0 */		/* set previous handler    */		signal(SIGWINCH, previous_SIGWINCH_handler);    /* reset    */}static void cmdedit_reset_term(void){	if ((handlers_sets & SET_RESET_TERM) != 0) {/* sparc and other have broken termios support: use old termio handling. */		setTermSettings(STDIN_FILENO, (void *) &initial_settings);		handlers_sets &= ~SET_RESET_TERM;	}	if ((handlers_sets & SET_WCHG_HANDLERS) != 0) {		/* reset SIGWINCH handler to previous (default) */		win_changed(0);		handlers_sets &= ~SET_WCHG_HANDLERS;	}	fflush(stdout);}/* special for recount position for scroll and remove terminal margin effect */static void cmdedit_set_out_char(int next_char){	int c = (int)((unsigned char) command_ps[cursor]);	if (c == 0)		c = ' ';        /* destroy end char? */#ifdef CONFIG_FEATURE_NONPRINTABLE_INVERSE_PUT	if (!Isprint(c)) {      /* Inverse put non-printable characters */		if (c >= 128)			c -= 128;		if (c < ' ')			c += '@';		if (c == 127)			c = '?';		printf("\033[7m%c\033[0m", c);	} else#endif		putchar(c);	if (++cmdedit_x >= cmdedit_termw) {		/* terminal is scrolled down */		cmdedit_y++;		cmdedit_x = 0;		if (!next_char)			next_char = ' ';		/* destroy "(auto)margin" */		putchar(next_char);		putchar('\b');	}	cursor++;}/* Move to end line. Bonus: rewrite line from cursor */static void input_end(void){	while (cursor < len)		cmdedit_set_out_char(0);}/* Go to the next line */static void goto_new_line(void){	input_end();	if (cmdedit_x)		putchar('\n');}static inline void out1str(const char *s){	if ( s )		fputs(s, stdout);}static inline void beep(void){	putchar('\007');}/* Move back one charactor *//* special for slow terminal */static void input_backward(int num){	if (num > cursor)		num = cursor;	cursor -= num;          /* new cursor (in command, not terminal) */	if (cmdedit_x >= num) {         /* no to up line */		cmdedit_x -= num;		if (num < 4)			while (num-- > 0)				putchar('\b');		else			printf("\033[%dD", num);	} else {		int count_y;		if (cmdedit_x) {			putchar('\r');          /* back to first terminal pos.  */			num -= cmdedit_x;       /* set previous backward        */		}		count_y = 1 + num / cmdedit_termw;		printf("\033[%dA", count_y);		cmdedit_y -= count_y;		/*  require  forward  after  uping   */		cmdedit_x = cmdedit_termw * count_y - num;		printf("\033[%dC", cmdedit_x);  /* set term cursor   */	}}static void put_prompt(void){	out1str(cmdedit_prompt);	cmdedit_x = cmdedit_prmt_len;   /* count real x terminal position */	cursor = 0;	cmdedit_y = 0;                  /* new quasireal y */}#ifndef CONFIG_FEATURE_SH_FANCY_PROMPTstatic void parse_prompt(const char *prmt_ptr){	cmdedit_prompt = prmt_ptr;	cmdedit_prmt_len = strlen(prmt_ptr);	put_prompt();}#elsestatic void parse_prompt(const char *prmt_ptr){	int prmt_len = 0;	int sub_len = 0;	char  flg_not_length = '[';	char *prmt_mem_ptr = xcalloc(1, 1);	char *pwd_buf = xgetcwd(0);	char  buf2[PATH_MAX + 1];	char  buf[2];	char  c;	char *pbuf;	if (!pwd_buf) {		pwd_buf=(char *)bb_msg_unknown;	}	while (*prmt_ptr) {		pbuf    = buf;		pbuf[1] = 0;		c = *prmt_ptr++;		if (c == '\\') {			const char *cp = prmt_ptr;			int l;			c = bb_process_escape_sequence(&prmt_ptr);			if(prmt_ptr==cp) {			  if (*cp == 0)				break;			  c = *prmt_ptr++;			  switch (c) {#ifdef CONFIG_FEATURE_GETUSERNAME_AND_HOMEDIR			  case 'u':				pbuf = user_buf;				break;#endif			  case 'h':				pbuf = hostname_buf;				if (pbuf == 0) {					pbuf = xcalloc(256, 1);					if (gethostname(pbuf, 255) < 0) {						strcpy(pbuf, "?");					} else {						char *s = strchr(pbuf, '.');						if (s)							*s = 0;					}					hostname_buf = pbuf;				}				break;			  case '$':				c = my_euid == 0 ? '#' : '$';				break;#ifdef CONFIG_FEATURE_GETUSERNAME_AND_HOMEDIR			  case 'w':				pbuf = pwd_buf;				l = strlen(home_pwd_buf);				if (home_pwd_buf[0] != 0 &&				    strncmp(home_pwd_buf, pbuf, l) == 0 &&				    (pbuf[l]=='/' || pbuf[l]=='\0') &&				    strlen(pwd_buf+l)<PATH_MAX) {					pbuf = buf2;					*pbuf = '~';					strcpy(pbuf+1, pwd_buf+l);					}				break;#endif			  case 'W':				pbuf = pwd_buf;				cp = strrchr(pbuf,'/');				if ( (cp != NULL) && (cp != pbuf) )					pbuf += (cp-pbuf)+1;				break;			  case '!':				snprintf(pbuf = buf2, sizeof(buf2), "%d", num_ok_lines);				break;			  case 'e': case 'E':     /* \e \E = \033 */				c = '\033';				break;			  case 'x': case 'X':				for (l = 0; l < 3;) {					int h;					buf2[l++] = *prmt_ptr;					buf2[l] = 0;					h = strtol(buf2, &pbuf, 16);					if (h > UCHAR_MAX || (pbuf - buf2) < l) {						l--;						break;					}					prmt_ptr++;				}				buf2[l] = 0;				c = (char)strtol(buf2, 0, 16);				if(c==0)					c = '?';				pbuf = buf;				break;			  case '[': case ']':				if (c == flg_not_length) {					flg_not_length = flg_not_length == '[' ? ']' : '[';					continue;				}				break;			  }			}		}		if(pbuf == buf)			*pbuf = c;		prmt_len += strlen(pbuf);		prmt_mem_ptr = strcat(xrealloc(prmt_mem_ptr, prmt_len+1), pbuf);		if (flg_not_length == ']')			sub_len++;	}	if(pwd_buf!=(char *)bb_msg_unknown)		free(pwd_buf);	cmdedit_prompt = prmt_mem_ptr;	cmdedit_prmt_len = prmt_len - sub_len;	put_prompt();}#endif/* draw promt, editor line, and clear tail */static void redraw(int y, int back_cursor){	if (y > 0)                              /* up to start y */		printf("\033[%dA", y);	putchar('\r');	put_prompt();	input_end();                            /* rewrite */	printf("\033[J");                       /* destroy tail after cursor */	input_backward(back_cursor);}/* Delete the char in front of the cursor */static void input_delete(void){	int j = cursor;	if (j == len)		return;	strcpy(command_ps + j, command_ps + j + 1);	len--;	input_end();                    /* rewtite new line */	cmdedit_set_out_char(0);        /* destroy end char */	input_backward(cursor - j);     /* back to old pos cursor */}/* Delete the char in back of the cursor */static void input_backspace(void){	if (cursor > 0) {		input_backward(1);		input_delete();	}}/* Move forward one charactor */static void input_forward(void){	if (cursor < len)		cmdedit_set_out_char(command_ps[cursor + 1]);}static void cmdedit_setwidth(int w, int redraw_flg){	cmdedit_termw = cmdedit_prmt_len + 2;	if (w <= cmdedit_termw) {		cmdedit_termw = cmdedit_termw % w;	}	if (w > cmdedit_termw) {		cmdedit_termw = w;		if (redraw_flg) {			/* new y for current cursor */			int new_y = (cursor + cmdedit_prmt_len) / w;			/* redraw */			redraw((new_y >= cmdedit_y ? new_y : cmdedit_y), len - cursor);			fflush(stdout);		}	}}static void cmdedit_init(void){	cmdedit_prmt_len = 0;	if ((handlers_sets & SET_WCHG_HANDLERS) == 0) {		/* emulate usage handler to set handler and call yours work */		win_changed(-SIGWINCH);		handlers_sets |= SET_WCHG_HANDLERS;	}	if ((handlers_sets & SET_ATEXIT) == 0) {#ifdef CONFIG_FEATURE_GETUSERNAME_AND_HOMEDIR		struct passwd *entry;		my_euid = geteuid();		entry = getpwuid(my_euid);		if (entry) {			user_buf = bb_xstrdup(entry->pw_name);			home_pwd_buf = bb_xstrdup(entry->pw_dir);		}#endif#ifdef  CONFIG_FEATURE_COMMAND_TAB_COMPLETION#ifndef CONFIG_FEATURE_GETUSERNAME_AND_HOMEDIR		my_euid = geteuid();#endif		my_uid = getuid();		my_gid = getgid();#endif  /* CONFIG_FEATURE_COMMAND_TAB_COMPLETION */		handlers_sets |= SET_ATEXIT;		atexit(cmdedit_reset_term);     /* be sure to do this only once */	}

⌨️ 快捷键说明

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