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

📄 getline.c

📁 ReactOS是一些高手根据Windows XP的内核编写出的类XP。内核实现机理和API函数调用几乎相同。甚至可以兼容XP的程序。喜欢研究系统内核的人可以看一看。
💻 C
📖 第 1 页 / 共 4 页
字号:
/* Based on: "$Id: getline.c 15091 2005-05-07 21:24:31Z sedwards $"; */
static const char copyright[] = "getline:  Copyright (C) 1991, 1992, 1993, Chris Thewalt";

/*
 * Copyright (C) 1991, 1992, 1993 by Chris Thewalt (thewalt@ce.berkeley.edu)
 *
 * Permission to use, copy, modify, and distribute this software
 * for any purpose and without fee is hereby granted, provided
 * that the above copyright notices appear in all copies and that both the
 * copyright notice and this permission notice appear in supporting
 * documentation.  This software is provided "as is" without express or
 * implied warranty.
 *
 * Thanks to the following people who have provided enhancements and fixes:
 *   Ron Ueberschaer, Christoph Keller, Scott Schwartz, Steven List,
 *   DaviD W. Sanderson, Goran Bostrom, Michael Gleason, Glenn Kasten,
 *   Edin Hodzic, Eric J Bivona, Kai Uwe Rommel, Danny Quah, Ulrich Betzler
 */

/*
 * Note:  This version has been updated by Mike Gleason <mgleason@ncftp.com>
 */

#if defined(WIN32) || defined(_WINDOWS)
#	include <windows.h>
#	include <sys/types.h>
#	include <sys/stat.h>
#	include <errno.h>
#	include <conio.h>
#	include <io.h>
#	include <fcntl.h>
#	define strcasecmp stricmp
#	define strncasecmp strnicmp
#	define sleep(a) Sleep(a * 1000)
#	ifndef S_ISREG
#		define S_ISREG(m)      (((m) & _S_IFMT) == _S_IFREG)
#		define S_ISDIR(m)      (((m) & _S_IFMT) == _S_IFDIR)
#	endif
#	ifndef open
#		define open _open
#		define write _write
#		define read _read
#		define close _close
#		define lseek _lseek
#		define stat _stat
#		define lstat _stat
#		define fstat _fstat
#		define dup _dup
#		define utime _utime
#		define utimbuf _utimbuf
#	endif
#	ifndef unlink
#		define unlink remove
#	endif
#	define NO_SIGNALS 1
#	define LOCAL_PATH_DELIM '\\'
#	define LOCAL_PATH_DELIM_STR "\\"
#	define LOCAL_PATH_ALTDELIM '/'
#	define IsLocalPathDelim(c) ((c == LOCAL_PATH_DELIM) || (c == LOCAL_PATH_ALTDELIM))
#	define UNC_PATH_PREFIX "\\\\"
#	define IsUNCPrefixed(s) (IsLocalPathDelim(s[0]) && IsLocalPathDelim(s[1]))
#	define __windows__ 1
#else
#	ifndef __unix__
#		define __unix__ 1
#	endif
#	if defined(AIX) || defined(_AIX)
#		define _ALL_SOURCE 1
#	endif
#	if defined(HAVE_CONFIG_H)
#		include <config.h>
#	else
#		/* guess */
#		define HAVE_TERMIOS_H 1
#		define HAVE_UNISTD_H 1
#	endif
#	ifdef HAVE_UNISTD_H
#		include <unistd.h>
#	endif
#	include <sys/types.h>
#	include <sys/time.h>
#	include <sys/stat.h>
#	ifdef CAN_USE_SYS_SELECT_H
#		include <sys/select.h>
#	endif
#	include <fcntl.h>
#	include <errno.h>
#	include <dirent.h>
#	include <pwd.h>
#	ifdef HAVE_TERMIOS_H		/* use HAVE_TERMIOS_H interface */
#		include <termios.h>
		struct termios  new_termios, old_termios;
#	else /* not HAVE_TERMIOS_H */
#		include <sys/ioctl.h>
#		ifdef TIOCSETN		/* use BSD interface */
#			include <sgtty.h>
			struct sgttyb   new_tty, old_tty;
			struct tchars   tch;
			struct ltchars  ltch;
#		else			/* use SYSV interface */
#			include <termio.h>
			struct termio   new_termio, old_termio;
#		endif /* TIOCSETN */
#	endif /* HAVE_TERMIOS_H */
#	define LOCAL_PATH_DELIM '/'
#	define LOCAL_PATH_DELIM_STR "/"
#	define _StrFindLocalPathDelim(a) strchr(a, LOCAL_PATH_DELIM)
#	define _StrRFindLocalPathDelim(a) strrchr(a, LOCAL_PATH_DELIM)
#	define IsLocalPathDelim(c) (c == LOCAL_PATH_DELIM)
#endif

/********************* C library headers ********************************/

#include <stdio.h>
#include <string.h>
#ifdef HAVE_STRINGS_H
#	include <strings.h>
#endif
#include <stdlib.h>
#include <ctype.h>
#include <signal.h>

#define _getline_c_ 1
#include "getline.h"

static int gl_tab(char *buf, int offset, int *loc, size_t bufsize);

/******************** external interface *********************************/

gl_in_hook_proc gl_in_hook = 0;
gl_out_hook_proc gl_out_hook = 0;
gl_tab_hook_proc gl_tab_hook = gl_tab;
gl_strlen_proc gl_strlen = (gl_strlen_proc) strlen;
gl_tab_completion_proc gl_completion_proc = 0;
int gl_filename_quoting_desired = -1;	/* default to unspecified */
const char *gl_filename_quote_characters = " \t*?<>|;&()[]$`";
int gl_ellipses_during_completion = 1;
int gl_completion_exact_match_extra_char;
char gl_buf[GL_BUF_SIZE];       /* input buffer */

/******************** internal interface *********************************/


static int      gl_init_done = -1;	/* terminal mode flag  */
static int      gl_termw = 80;		/* actual terminal width */
static int      gl_termh = 24;		/* actual terminal height */
static int      gl_scroll = 27;		/* width of EOL scrolling region */
static int      gl_width = 0;		/* net size available for input */
static int      gl_extent = 0;		/* how far to redraw, 0 means all */
static int      gl_overwrite = 0;	/* overwrite mode */
static int      gl_pos = 0, gl_cnt = 0; /* position and size of input */
static char     gl_killbuf[GL_BUF_SIZE]=""; /* killed text */
static const char *gl_prompt;		/* to save the prompt string */
static char     gl_intrc = 0;		/* keyboard SIGINT char */
static char     gl_quitc = 0;		/* keyboard SIGQUIT char */
static char     gl_suspc = 0;		/* keyboard SIGTSTP char */
static char     gl_dsuspc = 0;		/* delayed SIGTSTP char */
static int      gl_search_mode = 0;	/* search mode flag */
static char   **gl_matchlist = 0;
static char    *gl_home_dir = NULL;
static int      gl_vi_preferred = -1;
static int      gl_vi_mode = 0;
static int	gl_result = GL_OK;

static void     gl_init(void);		/* prepare to edit a line */
static void     gl_cleanup(void);	/* to undo gl_init */
static void     gl_char_init(void);	/* get ready for no echo input */
static void     gl_char_cleanup(void);	/* undo gl_char_init */
					/* returns printable prompt width */

static void     gl_addchar(int c);	/* install specified char */
static void     gl_del(int loc, int);	/* del, either left (-1) or cur (0) */
static void     gl_error(const char *const buf);	/* write error msg and die */
static void     gl_fixup(const char *prompt, int change, int cursor);		/* fixup state variables and screen */
static int      gl_getc(void);		/* read one char from terminal */
static int      gl_getcx(int);		/* read one char from terminal, if available before timeout */
static void     gl_kill(int pos);	/* delete to EOL */
static void     gl_newline(void);	/* handle \n or \r */
static void     gl_putc(int c);		/* write one char to terminal */
static void     gl_puts(const char *const buf);	/* write a line to terminal */
static void     gl_redraw(void);	/* issue \n and redraw all */
static void     gl_transpose(void);	/* transpose two chars */
static void     gl_yank(void);		/* yank killed text */
static void     gl_word(int direction);	/* move a word */
static void     gl_killword(int direction);

static void     hist_init(void);	/* initializes hist pointers */
static char    *hist_next(void);	/* return ptr to next item */
static char    *hist_prev(void);	/* return ptr to prev item */
static char    *hist_save(char *p);	/* makes copy of a string, without NL */

static void     search_addchar(int c);	/* increment search string */
static void     search_term(void);	/* reset with current contents */
static void     search_back(int new_search);		/* look back for current string */
static void     search_forw(int new_search);		/* look forw for current string */
static void     gl_beep(void);          /* try to play a system beep sound */

static int      gl_do_tab_completion(char *buf, int *loc, size_t bufsize, int tabtab);

/************************ nonportable part *********************************/

#ifdef MSDOS
#include <bios.h>
#endif

static void
gl_char_init(void)			/* turn off input echo */
{
#ifdef __unix__
#	ifdef HAVE_TERMIOS_H		/* Use POSIX */
		if (tcgetattr(0, &old_termios) == 0) {
			gl_intrc = old_termios.c_cc[VINTR];
			gl_quitc = old_termios.c_cc[VQUIT];
#		ifdef VSUSP
			gl_suspc = old_termios.c_cc[VSUSP];
#		endif
#		ifdef VDSUSP
			gl_dsuspc = old_termios.c_cc[VDSUSP];
#		endif
		}
		new_termios = old_termios;
		new_termios.c_iflag &= ~(BRKINT|ISTRIP|IXON|IXOFF);
		new_termios.c_iflag |= (IGNBRK|IGNPAR);
		new_termios.c_lflag &= ~(ICANON|ISIG|IEXTEN|ECHO);
		new_termios.c_cc[VMIN] = 1;
		new_termios.c_cc[VTIME] = 0;
		tcsetattr(0, TCSANOW, &new_termios);
#	elif defined(TIOCSETN)		/* BSD */
		if (ioctl(0, TIOCGETC, &tch) == 0) {
			gl_intrc = tch.t_intrc;
			gl_quitc = tch.t_quitc;
		}
		ioctl(0, TIOCGLTC, &ltch);
		gl_suspc = ltch.t_suspc;
		gl_dsuspc = ltch.t_dsuspc;
		ioctl(0, TIOCGETP, &old_tty);
		new_tty = old_tty;
		new_tty.sg_flags |= RAW;
		new_tty.sg_flags &= ~ECHO;
		ioctl(0, TIOCSETN, &new_tty);
#	else				/* SYSV */
		if (ioctl(0, TCGETA, &old_termio) == 0) {
			gl_intrc = old_termio.c_cc[VINTR];
			gl_quitc = old_termio.c_cc[VQUIT];
		}
		new_termio = old_termio;
		new_termio.c_iflag &= ~(BRKINT|ISTRIP|IXON|IXOFF);
		new_termio.c_iflag |= (IGNBRK|IGNPAR);
		new_termio.c_lflag &= ~(ICANON|ISIG|ECHO);
		new_termio.c_cc[VMIN] = 1;
		new_termio.c_cc[VTIME] = 0;
		ioctl(0, TCSETA, &new_termio);
#	endif
#endif /* __unix__ */
}

static void
gl_char_cleanup(void)		/* undo effects of gl_char_init */
{
#ifdef __unix__
#	ifdef HAVE_TERMIOS_H
		tcsetattr(0, TCSANOW, &old_termios);
#	elif defined(TIOCSETN)		/* BSD */
		ioctl(0, TIOCSETN, &old_tty);
#	else			/* SYSV */
		ioctl(0, TCSETA, &old_termio);
#	endif
#endif /* __unix__ */
}



int
gl_get_result(void)
{
	return (gl_result);
}	/* gl_get_result */




#if defined(MSDOS) || defined(__windows__)

#define K_UP				0x48
#define K_DOWN				0x50
#define K_LEFT				0x4B
#define K_RIGHT				0x4D
#define K_DELETE			0x53
#define K_INSERT			0x52
#define K_HOME				0x47
#define K_END				0x4F
#define K_PGUP				0x49
#define K_PGDN				0x51

int pc_keymap(int c)
{
    switch (c) {
	case K_UP:
	case K_PGUP:
		c = 16;		/* up -> ^P */
        break;
	case K_DOWN:
	case K_PGDN:
		c = 14;		/* down -> ^N */
        break;
    case K_LEFT:
		c = 2;		/* left -> ^B */
        break;
    case K_RIGHT:
		c = 6;		/* right -> ^F */
        break;
	case K_END:
		c = 5;		/* end -> ^E */
		break;
	case K_HOME:
		c = 1;		/* home -> ^A */
		break;
	case K_INSERT:
		c = 15;		/* insert -> ^O */
		break;
	case K_DELETE:
		c = 4;		/* del -> ^D */
		break;
    default:
		c = 0;    /* make it garbage */
    }
    return c;
}
#endif /* defined(MSDOS) || defined(__windows__) */

static int
gl_getc(void)
/* get a character without echoing it to screen */
{
    int             c;
#ifdef __unix__
    char            ch;
#endif

#ifdef __unix__
    ch = '\0';
    while ((c = (int) read(0, &ch, 1)) == -1) {
	if (errno != EINTR)
	    break;
    }
    if (c != (-1))
	    c = (int) ch;
#endif	/* __unix__ */
#ifdef MSDOS
    c = _bios_keybrd(_NKEYBRD_READ);
    if ((c & 0377) == 224) {
	c = pc_keymap((c >> 8) & 0377);
    } else {
	c &= 0377;
    }
#endif /* MSDOS */
#ifdef __windows__
	c = (int) _getch();
	if ((c == 0) || (c == 0xE0)) {
		/* Read key code */
		c = (int) _getch();
		c = pc_keymap(c);
	} else if (c == '\r') {
		/* Note: we only get \r from the console,
		 * and not a matching \n.
		 */
		c = '\n';
	}
#endif
    return c;
}



#ifdef __unix__

static int
gl_getcx(int tlen)
/* Get a character without echoing it to screen, timing out
 * after tlen tenths of a second.
 */
{
	int c, result;
	char ch;
	fd_set ss;
	struct timeval tv;

	for (errno = 0;;) {
		FD_ZERO(&ss);
		FD_SET(0, &ss);		/* set STDIN_FILENO */
		tv.tv_sec = tlen / 10;
		tv.tv_usec = (tlen % 10) * 100000L;
		result = select(1, &ss, NULL, NULL, &tv);
		if (result == 1) {
			/* ready */
			break;
		} else if (result == 0) {
			errno = ETIMEDOUT;
			return (-2);
		} else if (errno != EINTR) {
			return (-1);
		}
	}

	for (errno = 0;;) {
		c = (int) read(0, &ch, 1);
		if (c == 1)
			return ((int) ch);
		if (errno != EINTR)
			break;
	}

	return (-1);
}	/* gl_getcx */

#endif	/* __unix__ */




#ifdef __windows__

static int
gl_getcx(int tlen)
{
	int i, c;

	c = (-2);
	tlen -= 2;	/* Adjust for 200ms overhead */
	if (tlen < 1)
		tlen = 1;
	for (i=0; i<tlen; i++) {
		if (_kbhit()) {
			c = (int) _getch();
			if ((c == 0) || (c == 0xE0)) {
				/* Read key code */
				c = (int) _getch();
				c = pc_keymap(c);
				break;
			}
		}
		(void) SleepEx((DWORD) (tlen * 100), FALSE);
	}
	return (c);
}	/* gl_getcx */

#endif	/* __windows__ */




static void
gl_putc(int c)
{
    char   ch = (char) (unsigned char) c;

    write(1, &ch, 1);
    if (ch == '\n') {
	ch = '\r';
        write(1, &ch, 1);	/* RAW mode needs '\r', does not hurt */
    }
}

/******************** fairly portable part *********************************/

static void
gl_puts(const char *const buf)
{
    int len;

    if (buf) {
        len = (int) strlen(buf);
        write(1, buf, len);
    }
}

static void
gl_error(const char *const buf)
{
    int len = (int) strlen(buf);

    gl_cleanup();
    write(2, buf, len);
    exit(1);
}

static void
gl_init(void)
/* set up variables and terminal */
{
    const char *cp;
    int w;

    if (gl_init_done < 0) {		/* -1 only on startup */
	cp = (const char *) getenv("COLUMNS");
	if (cp != NULL) {
	    w = atoi(cp);
	    if (w > 20)
	        gl_setwidth(w);
	}
	cp = (const char *) getenv("ROWS");
	if (cp != NULL) {
	    w = atoi(cp);
	    if (w > 10)
	        gl_setheight(w);
	}
        hist_init();
    }
    if (isatty(0) == 0 || isatty(1) == 0)
	gl_error("\n*** Error: getline(): not interactive, use stdio.\n");
    gl_char_init();
    gl_init_done = 1;
}

static void
gl_cleanup(void)
/* undo effects of gl_init, as necessary */
{
    if (gl_init_done > 0)
        gl_char_cleanup();
    gl_init_done = 0;
#ifdef __windows__
	Sleep(40);
	FlushConsoleInputBuffer(GetStdHandle(STD_INPUT_HANDLE));
#endif
}


static void
gl_check_inputrc_for_vi(void)
{
	FILE *fp;
	char path[256];

	/* If the user has a ~/.inputrc file,
	 * check it to see if it has a line like
	 * "set editing-mode vi".  If it does,
	 * we know that the user wants vi
	 * emulation rather than emacs.  If the
	 * file doesn't exist, it's no big
	 * deal since we can also check the
	 * $EDITOR environment variable.
	 */
	gl_set_home_dir(NULL);
	if (gl_home_dir == NULL)
		return;

#ifdef HAVE_SNPRINTF
	snprintf(path, sizeof(path), "%s/%s", gl_home_dir, ".inputrc");
#else
	if (sizeof(path) >= (strlen(gl_home_dir) + strlen("/.inputrc")))
		return;

	sprintf(path, "%s%s", gl_home_dir, "/.inputrc");
#endif

	fp = fopen(
		path,
#if defined(__windows__) || defined(MSDOS)
		"rt"
#else
		"r"
#endif
	);

	if (fp == NULL)
		return;

	while (fgets(path, sizeof(path) - 1, fp) != NULL) {
		if ((strstr(path, "editing-mode") != NULL) && (strstr(path, "vi") != NULL)) {
			gl_vi_preferred = 1;
			break;
		}
	}

	(void) fclose(fp);
}	/* gl_check_inputrc_for_vi */



void
gl_setwidth(int w)
{
    if (w > 250)
    	w = 250;
    if (w > 20) {
	gl_termw = w;
	gl_scroll = w / 3;
    } else {
	gl_error("\n*** Error: minimum screen width is 21\n");
    }
}	/* gl_setwidth */



void
gl_setheight(int w)
{
    if (w > 10) {
	gl_termh = w;
    } else {
	gl_error("\n*** Error: minimum screen height is 10\n");
    }
}	/* gl_setheight */




char *
getline(char *prompt)
{
    int             c, loc, tmp, lastch;
    int vi_count, count;
    int vi_delete;
    char vi_countbuf[32];
    char *cp;

#ifdef __unix__
    int	            sig;

⌨️ 快捷键说明

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