ftp.nice.ch/pub/next/unix/editor/vim-5.0f.s.tar.gz#/vim-5.0f/src/ui.c

This is ui.c in view mode; [Download] [Up]

/* vi:set ts=4 sw=4:
 *
 * VIM - Vi IMproved		by Bram Moolenaar
 *
 * Do ":help uganda"  in Vim to read copying and usage conditions.
 * Do ":help credits" in Vim to see a list of people who contributed.
 */

/*
 * ui.c: functions that handle the user interface.
 * 1. Keyboard input stuff, and a bit of windowing stuff.  These are called
 *    before the machine specific stuff (mch_*) so that we can call the GUI
 *    stuff instead if the GUI is running.
 * 2. Clipboard stuff.
 * 3. Input buffer stuff.
 */

#include "vim.h"
#include "globals.h"
#include "proto.h"
#include "option.h"

	void
ui_write(s, len)
	char_u	*s;
	int		len;
{
#ifdef USE_GUI
	if (gui.in_use && !gui.dying)
	{
		gui_write(s, len);
		if (p_wd)
			gui_wait_for_chars(p_wd);
		return;
	}
#endif
	mch_write(s, len);
}

/*
 * ui_inchar(): low level input funcion.
 * Get a characters from the keyboard.
 * Return the number of characters that are available.
 * If wtime == 0 do not wait for characters.
 * If wtime == -1 wait forever for characters.
 * If wtime > 0 wait wtime milliseconds for a character.
 */
	int
ui_inchar(buf, maxlen, wtime)
	char_u	*buf;
	int		maxlen;
	long	wtime;			/* don't use "time", MIPS cannot handle it */
{
#ifdef USE_GUI
	if (gui.in_use)
	{
		if (!gui_wait_for_chars(wtime))
			return 0;
		return read_from_input_buf(buf, (long)maxlen);
	}
#endif
	return mch_inchar(buf, maxlen, wtime);
}

/*
 * return non-zero if a character is available
 */
	int
ui_char_avail()
{
#ifdef USE_GUI
	if (gui.in_use)
	{
		gui_mch_update();
		return !is_input_buf_empty();
	}
#endif
	return mch_char_avail();
}

/*
 * Delay for the given number of milliseconds.  If ignoreinput is FALSE then we
 * cancel the delay if a key is hit.
 */
	void
ui_delay(msec, ignoreinput)
	long		msec;
	int			ignoreinput;
{
#ifdef USE_GUI
	if (gui.in_use && !ignoreinput)
		gui_wait_for_chars(msec);
	else
#endif
		mch_delay(msec, ignoreinput);
}

/*
 * If the machine has job control, use it to suspend the program,
 * otherwise fake it by starting a new shell.
 * When running the GUI iconify the window.
 */
	void
ui_suspend()
{
#ifdef USE_GUI
	if (gui.in_use)
	{
		gui_mch_iconify();
		return;
	}
#endif
	mch_suspend();
}

/*
 * When the OS can't really suspend, call this function to start a shell.
 */
	void
suspend_shell()
{
	MSG_PUTS("new shell started\n");
	mch_call_shell(NULL, SHELL_COOKED);
	need_check_timestamps = TRUE;
}

	int
ui_can_restore_title()
{
#ifdef USE_GUI
	/*
	 * If GUI is (going to be) used, we can always set the window title.
	 * Saves a bit of time, because the X11 display server does not need to be
	 * contacted.
	 */
	if (gui.starting || gui.in_use)
		return TRUE;
#endif
	return mch_can_restore_title();
}

	int
ui_can_restore_icon()
{
#ifdef USE_GUI
	/*
	 * If GUI is (going to be) used, we can always set the icon name.
	 * Saves a bit of time, because the X11 display server does not need to be
	 * contacted.
	 */
	if (gui.starting || gui.in_use)
		return TRUE;
#endif
	return mch_can_restore_icon();
}

/*
 * Try to get the current window size.  Put the result in Rows and Columns.
 */
	int
ui_get_winsize()
{
#ifdef USE_GUI
	if (gui.in_use)
		return gui_get_winsize();
#endif
	return mch_get_winsize();
}

/*
 * Set the size of the window according to Rows and Columns, if possible.
 */
	void
ui_set_winsize()
{
#ifdef USE_GUI
	if (gui.in_use)
		gui_set_winsize(FALSE);
	else
#endif
		mch_set_winsize();
}

	void
ui_breakcheck()
{
#ifdef USE_GUI
	if (gui.in_use)
		gui_mch_update();
	else
#endif /* USE_GUI */
		mch_breakcheck();
}

/*****************************************************************************
 * Functions for copying and pasting text between applications.
 * This is always included in a GUI version, but may also be included when the
 * clipboard and mouse is available to a terminal version such as xterm.
 * Note: there are some more functions in ops.c that handle selection stuff.
 */

#ifdef USE_CLIPBOARD

/* All the clipboard info */
VimClipboard clipboard;

static void clip_own_selection __ARGS((void));
static void clip_invert_area __ARGS((int, int, int, int));
static void clip_yank_non_visual_selection __ARGS((int, int, int, int));
static void clip_get_word_boundaries __ARGS((VimClipboard *, int, int));
static int  clip_get_line_end __ARGS((int));
static void clip_update_non_visual_selection __ARGS((VimClipboard *, int, int,
													int, int));

#define char_class(c)	(c <= ' ' ? ' ' : iswordchar(c))

/*
 * Selection stuff using Visual mode, for cutting and pasting text to other
 * windows.
 */

/*
 * Call this to initialise the clipboard.  Pass it FALSE if the clipboard code
 * is included, but the clipboard can not be used, or TRUE if the clipboard can
 * be used.  Eg unix may call this with FALSE, then call it again with TRUE if
 * the GUI starts.
 */
	void
clip_init(can_use)
	int		can_use;
{
	clipboard.available = can_use;
	clipboard.owned = FALSE;
	clipboard.start.lnum = 0;
	clipboard.start.col = 0;
	clipboard.end.lnum = 0;
	clipboard.end.col = 0;
	clipboard.state = SELECT_CLEARED;
}

/*
 * Check whether the VIsual area has changed, and if so try to become the owner
 * of the selection, and free any old converted selection we may still have
 * lying around.  If the VIsual mode has ended, make a copy of what was
 * selected so we can still give it to others.  Will probably have to make sure
 * this is called whenever VIsual mode is ended.
 */
	void
clip_update_selection()
{
	/* If visual mode is only due to a redo command ("."), then ignore it */
	if (redo_VIsual_busy)
		return;
	if (!VIsual_active)
	{
		clip_clear_selection();
		clipboard.start = clipboard.end = VIsual;
	}
	else if (lt(VIsual, curwin->w_cursor))
	{
		if (!equal(clipboard.start, VIsual) ||
			!equal(clipboard.end, curwin->w_cursor))
		{
			clip_clear_selection();
			clipboard.start = VIsual;
			clipboard.end = curwin->w_cursor;
			clip_free_selection();
			clip_own_selection();
		}
	}
	else
	{
		if (!equal(clipboard.start, curwin->w_cursor) ||
			!equal(clipboard.end, VIsual))
		{
			clip_clear_selection();
			clipboard.start = curwin->w_cursor;
			clipboard.end = VIsual;
			clip_free_selection();
			clip_own_selection();
		}
	}
}

	static void
clip_own_selection()
{
	/*
	 * Also want to check somehow that we are reading from the keyboard rather
	 * than a mapping etc.
	 */
	if (!clipboard.owned)
	{
		clipboard.owned = TRUE;
		if (clip_mch_own_selection())		/* May alter clipboard.owned */
			clip_free_selection();
		else
			clipboard.owned = FALSE;
	}
}

	void
clip_lose_selection()
{
	clip_free_selection();
	clipboard.owned = FALSE;
	clip_clear_selection();
	clip_mch_lose_selection();
}

	void
clip_copy_selection()
{
	if (VIsual_active)
	{
		if (vim_strchr(p_guioptions, GO_ASEL) == NULL)
			clip_update_selection();
		clip_own_selection();
		if (clipboard.owned)
			clip_get_selection();
	}
}

	void
clip_auto_select()
{
	if (vim_strchr(p_guioptions, GO_ASEL) != NULL)
		clip_copy_selection();
}


#ifdef USE_GUI

/*
 * Stuff for general mouse selection, without using Visual mode.
 */

static int clip_compare_pos __ARGS((int row1, int col1, int row2, int col2));

/*
 * Compare two screen positions ala strcmp()
 */
	static int
clip_compare_pos(row1, col1, row2, col2)
	int		row1;
	int		col1;
	int		row2;
	int		col2;
{
	if (row1 > row2) return( 1);
	if (row1 < row2) return(-1);
	if (col1 > col2) return( 1);
	if (col1 < col2) return(-1);
					 return( 0);
}

/*
 * Start out the selection
 */
	void
clip_start_selection(button, x, y, repeated_click, modifiers)
	int		button;
	int		x;
	int		y;
	int		repeated_click;
	int_u	modifiers;
{
	VimClipboard	*cb = &clipboard;

	if (cb->state == SELECT_DONE)
		clip_clear_selection();

	cb->start.lnum	= Y_2_ROW(y);
	cb->start.col	= X_2_COL(x);
	cb->end			= cb->start;
	cb->origin_row	= (short_u)cb->start.lnum;
	cb->state		= SELECT_IN_PROGRESS;

	if (repeated_click)
	{
		if (++(cb->mode) > SELECT_MODE_LINE)
			cb->mode = SELECT_MODE_CHAR;
	}
	else
		cb->mode = SELECT_MODE_CHAR;

#ifdef USE_GUI
	/* clear the cursor until the selection is made */
	gui_undraw_cursor();
#endif

	switch (cb->mode)
	{
		case SELECT_MODE_CHAR:
			cb->origin_start_col = cb->start.col;
			cb->word_end_col = clip_get_line_end(cb->start.lnum);
			break;

		case SELECT_MODE_WORD:
			clip_get_word_boundaries(cb, cb->start.lnum, cb->start.col);
			cb->origin_start_col = cb->word_start_col;
			cb->origin_end_col   = cb->word_end_col;

			clip_invert_area(cb->start.lnum, cb->word_start_col,
							cb->end.lnum, cb->word_end_col);
			cb->start.col = cb->word_start_col;
			cb->end.col   = cb->word_end_col;
			break;

		case SELECT_MODE_LINE:
			clip_invert_area(cb->start.lnum, 0, cb->start.lnum,
							Columns);
			cb->start.col = 0;
			cb->end.col   = Columns;
			break;
	}

	cb->prev = cb->start;

#ifdef DEBUG_SELECTION
	printf("Selection started at (%u,%u)\n", cb->start.lnum, cb->start.col);
#endif
}

/*
 * Continue processing the selection
 */
	void
clip_process_selection(button, x, y, repeated_click, modifiers)
	int		button;
	int		x;
	int		y;
	int		repeated_click;
	int_u	modifiers;
{
	VimClipboard	*cb = &clipboard;
	int				row;
	int_u			col;
	int				diff;

	if (button == MOUSE_RELEASE)
	{
		/* Check to make sure we have something selected */
		if (cb->start.lnum == cb->end.lnum && cb->start.col == cb->end.col)
		{
#ifdef USE_GUI
			gui_update_cursor(FALSE);
#endif
			cb->state = SELECT_CLEARED;
			return;
		}

#ifdef DEBUG_SELECTION
		printf("Selection ended: (%u,%u) to (%u,%u)\n", cb->start.lnum,
				cb->start.col, cb->end.lnum, cb->end.col);
#endif
		clip_free_selection();
		clip_own_selection();
		clip_yank_non_visual_selection(cb->start.lnum, cb->start.col,
												   cb->end.lnum, cb->end.col);
#ifdef USE_GUI
		gui_update_cursor(FALSE);
#endif

		cb->state = SELECT_DONE;
		return;
	}

	row = Y_2_ROW(y);
	col = X_2_COL(x);

	row = check_row(row);
	col = check_col(col);

	if (col == cb->prev.col && row == cb->prev.lnum)
		return;

	/*
	 * When extending the selection with the right mouse button, swap the
	 * start and end if the position is before half the selection
	 */
	if (cb->state == SELECT_DONE && button == MOUSE_RIGHT)
	{
		/*
		 * If the click is before the start, or the click is inside the
		 * selection and the start is the closest side, set the origin to the
		 * end of the selection.
		 */
		if (clip_compare_pos(row, col, cb->start.lnum, cb->start.col) < 0 ||
				(clip_compare_pos(row, col, cb->end.lnum, cb->end.col) < 0 &&
				 (((cb->start.lnum == cb->end.lnum &&
					cb->end.col - col > col - cb->start.col)) ||
				  ((diff = (cb->end.lnum - row) - (row - cb->start.lnum)) > 0 ||
				   (diff == 0 && col < (cb->start.col + cb->end.col) / 2)))))
		{
			cb->origin_row = (short_u)cb->end.lnum;
			cb->origin_start_col = cb->end.col - 1;
			cb->origin_end_col = cb->end.col;
		}
		else
		{
			cb->origin_row = (short_u)cb->start.lnum;
			cb->origin_start_col = cb->start.col;
			cb->origin_end_col = cb->start.col;
		}
		if (cb->mode == SELECT_MODE_WORD)
		{
			clip_get_word_boundaries(cb, cb->origin_row, cb->origin_start_col);
			cb->origin_start_col = cb->word_start_col;
			cb->origin_end_col   = cb->word_end_col;
		}
	}

	/* set state, for when using the right mouse button */
	cb->state = SELECT_IN_PROGRESS;

#ifdef DEBUG_SELECTION
	printf("Selection extending to (%d,%d)\n", row, col);
#endif

	switch (cb->mode)
	{
		case SELECT_MODE_CHAR:
			/* If we're on a different line, find where the line ends */
			if (row != cb->prev.lnum)
				cb->word_end_col = clip_get_line_end(row);

			/* See if we are before or after the origin of the selection */
			if (clip_compare_pos(row, col, cb->origin_row,
												   cb->origin_start_col) >= 0)
			{
				if (col >= (int)cb->word_end_col)
					clip_update_non_visual_selection(cb, cb->origin_row,
							cb->origin_start_col, row, Columns);
				else
					clip_update_non_visual_selection(cb, cb->origin_row,
							cb->origin_start_col, row, col + 1);
			}
			else
			{
				if (col >= (int)cb->word_end_col)
					clip_update_non_visual_selection(cb, row, cb->word_end_col,
							cb->origin_row, cb->origin_start_col + 1);
				else
					clip_update_non_visual_selection(cb, row, col,
							cb->origin_row, cb->origin_start_col + 1);
			}
			break;

		case SELECT_MODE_WORD:
			/* If we are still within the same word, do nothing */
			if (row == cb->prev.lnum && col >= (int)cb->word_start_col
					&& col < (int)cb->word_end_col)
				return;

			/* Get new word boundaries */
			clip_get_word_boundaries(cb, row, col);

			/* Handle being after the origin point of selection */
			if (clip_compare_pos(row, col, cb->origin_row,
					cb->origin_start_col) >= 0)
				clip_update_non_visual_selection(cb, cb->origin_row,
						cb->origin_start_col, row, cb->word_end_col);
			else
				clip_update_non_visual_selection(cb, row, cb->word_start_col,
						cb->origin_row, cb->origin_end_col);
			break;

		case SELECT_MODE_LINE:
			if (row == cb->prev.lnum)
				return;

			if (clip_compare_pos(row, col, cb->origin_row,
					cb->origin_start_col) >= 0)
				clip_update_non_visual_selection(cb, cb->origin_row, 0, row,
						Columns);
			else
				clip_update_non_visual_selection(cb, row, 0, cb->origin_row,
						Columns);
			break;
	}

	cb->prev.lnum = row;
	cb->prev.col  = col;

#ifdef DEBUG_SELECTION
		printf("Selection is: (%u,%u) to (%u,%u)\n", cb->start.lnum,
				cb->start.col, cb->end.lnum, cb->end.col);
#endif
}

/*
 * Called after an Expose event to redraw the selection
 */
	void
clip_redraw_selection(x, y, w, h)
	int		x;
	int		y;
	int		w;
	int		h;
{
	VimClipboard	*cb = &clipboard;
	int				row1, col1, row2, col2;
	int				row;
	int				start;
	int				end;

	if (cb->state == SELECT_CLEARED)
		return;

#ifdef USE_GUI		/* TODO: how do we invert for non-GUI versions? */
	row1 = Y_2_ROW(y);
	col1 = X_2_COL(x);
	row2 = Y_2_ROW(y + h - 1);
	col2 = X_2_COL(x + w - 1);

	/* Limit the rows that need to be re-drawn */
	if (cb->start.lnum > row1)
		row1 = cb->start.lnum;
	if (cb->end.lnum < row2)
		row2 = cb->end.lnum;

	/* Look at each row that might need to be re-drawn */
	for (row = row1; row <= row2; row++)
	{
		/* For the first selection row, use the starting selection column */
		if (row == cb->start.lnum)
			start = cb->start.col;
		else
			start = 0;

		/* For the last selection row, use the ending selection column */
		if (row == cb->end.lnum)
			end = cb->end.col;
		else
			end = Columns;

		if (col1 > start)
			start = col1;

		if (col2 < end)
			end = col2 + 1;

		if (end > start)
			gui_mch_invert_rectangle(row, start, 1, end - start);
	}
#endif
}

/*
 * Called from outside to clear selected region from the display
 */
	void
clip_clear_selection()
{
	VimClipboard	*cb = &clipboard;

	if (cb->state == SELECT_CLEARED)
		return;

	clip_invert_area(cb->start.lnum, cb->start.col, cb->end.lnum,
			cb->end.col);
	cb->state = SELECT_CLEARED;
}

/*
 * Invert a region of the display between a starting and ending row and column
 */
	static void
clip_invert_area(row1, col1, row2, col2)
	int		row1;
	int		col1;
	int		row2;
	int		col2;
{
#ifdef USE_GUI		/* TODO: how do we invert for non-GUI versions? */
	/* Swap the from and to positions so the from is always before */
	if (clip_compare_pos(row1, col1, row2, col2) > 0)
	{
		int tmp_row, tmp_col;
		tmp_row = row1;
		tmp_col = col1;
		row1	= row2;
		col1	= col2;
		row2	= tmp_row;
		col2	= tmp_col;
	}

	/* If all on the same line, do it the easy way */
	if (row1 == row2)
	{
		gui_mch_invert_rectangle(row1, col1, 1, col2 - col1);
		return;
	}

	/* Handle a piece of the first line */
	if (col1 > 0)
	{
		gui_mch_invert_rectangle(row1, col1, 1, Columns - col1);
		row1++;
	}

	/* Handle a piece of the last line */
	if (col2 < Columns - 1)
	{
		gui_mch_invert_rectangle(row2, 0, 1, col2);
		row2--;
	}

	/* Handle the rectangle thats left */
	if (row2 >= row1)
		gui_mch_invert_rectangle(row1, 0, row2 - row1 + 1, Columns);
#endif
}

/*
 * Yank the currently selected area into the special selection buffer so it
 * will be available for pasting.
 */
	static void
clip_yank_non_visual_selection(row1, col1, row2, col2)
	int		row1;
	int		col1;
	int		row2;
	int		col2;
{
	char_u	*buffer;
	char_u	*bufp;
	int		row;
	int		start_col;
	int		end_col;
	int		line_end_col;
	int		add_newline_flag = FALSE;

	/*
	 * Make sure row1 <= row2, and if row1 == row2 that col1 <= col2.
	 */
	if (row1 > row2)
	{
		row = row1; row1 = row2; row2 = row;
		row = col1; col1 = col2; col2 = row;
	}
	else if (row1 == row2 && col1 > col2)
	{
		row = col1; col1 = col2; col2 = row;
	}

	/* Create a temporary buffer for storing the text */
	buffer = lalloc((row2 - row1 + 1) * Columns + 1, TRUE);
	if (buffer == NULL)		/* out of memory */
		return;

	/* Process each row in the selection */
	for (bufp = buffer, row = row1; row <= row2; row++)
	{
		if (row == row1)
			start_col = col1;
		else
			start_col = 0;

		if (row == row2)
			end_col = col2;
		else
			end_col = Columns;

		line_end_col = clip_get_line_end(row);

		/* See if we need to nuke some trailing whitespace */
		if (end_col >= Columns && (row < row2 || end_col > line_end_col))
		{
			/* Get rid of trailing whitespace */
			end_col = line_end_col;
			if (end_col < start_col)
				end_col = start_col;

			/* If the last line extended to the end, add an extra newline */
			if (row == row2)
				add_newline_flag = TRUE;
		}

		/* If after the first row, we need to always add a newline */
		if (row > row1)
			*bufp++ = NL;

		if (row < screen_Rows && end_col <= screen_Columns)
		{
			STRNCPY(bufp, &LinePointers[row][start_col], end_col - start_col);
			bufp += end_col - start_col;
		}
	}

	/* Add a newline at the end if the selection ended there */
	if (add_newline_flag)
		*bufp++ = NL;

	clip_yank_selection(MCHAR, buffer, bufp - buffer);
	vim_free(buffer);
}

/*
 * Find the starting and ending positions of the word at the given row and
 * column.
 */
	static void
clip_get_word_boundaries(cb, row, col)
	VimClipboard	*cb;
	int				row;
	int				col;
{
	char	start_class;
	int		temp_col;

	if (row >= screen_Rows || col >= screen_Columns)
		return;

	start_class = char_class(LinePointers[row][col]);

	temp_col = col;
	for ( ; temp_col > 0; temp_col--)
		if (char_class(LinePointers[row][temp_col - 1]) != start_class)
			break;

	cb->word_start_col = temp_col;

	temp_col = col;
	for ( ; temp_col < screen_Columns; temp_col++)
		if (char_class(LinePointers[row][temp_col]) != start_class)
			break;
	cb->word_end_col = temp_col;

#ifdef DEBUG_SELECTION
	printf("Current word: col %u to %u\n", cb->word_start_col,
			cb->word_end_col);
#endif
}

/*
 * Find the column position for the last non-whitespace character on the given
 * line.
 */
	static int
clip_get_line_end(row)
	int			row;
{
	int		i;

	if (row >= screen_Rows)
		return 0;
	for (i = screen_Columns; i > 0; i--)
		if (LinePointers[row][i - 1] != ' ')
			break;
	return i;
}

/*
 * Update the currently selected region by adding and/or subtracting from the
 * beginning or end and inverting the changed area(s).
 */
	static void
clip_update_non_visual_selection(cb, row1, col1, row2, col2)
	VimClipboard	*cb;
	int				row1;
	int				col1;
	int				row2;
	int				col2;
{
	/* See if we changed at the beginning of the selection */
	if (row1 != cb->start.lnum || col1 != (int)cb->start.col)
	{
		clip_invert_area(row1, col1, cb->start.lnum, cb->start.col);
		cb->start.lnum = row1;
		cb->start.col  = col1;
	}

	/* See if we changed at the end of the selection */
	if (row2 != cb->end.lnum || col2 != (int)cb->end.col)
	{
		clip_invert_area(row2, col2, cb->end.lnum, cb->end.col);
		cb->end.lnum = row2;
		cb->end.col  = col2;
	}
}

#else /* If USE_GUI not defined */

/*
 * Called from outside to clear selected region from the display
 */
	void
clip_clear_selection()
{
    /*
	 * Dummy version for now... the point of this code is to set the selected
	 * area back to "normal" colour if we are clearing the selection. As we
	 * don't have GUI-style mouse selection, we can ignore this for now.
	 * Eventually we could actually invert the area in a terminal by redrawing
	 * in reverse mode, but we don't do that yet.
     */
    clipboard.state = SELECT_CLEARED;
}
#endif /* USE_GUI */


#endif /* USE_CLIPBOARD */

/*****************************************************************************
 * Functions that handle the input buffer.
 * This is used for any GUI version, and the unix terminal version.
 *
 * For Unix, the input characters are buffered to be able to check for a
 * CTRL-C.  This should be done with signals, but I don't know how to do that
 * in a portable way for a tty in RAW mode.
 */

#if defined(UNIX) || defined(USE_GUI) || defined(OS2)

/*
 * Internal typeahead buffer.  Includes extra space for long key code
 * descriptions which would otherwise overflow.  The buffer is considered full
 * when only this extra space (or part of it) remains.
 */
#define INBUFLEN 250

static char_u	inbuf[INBUFLEN + MAX_KEY_CODE_LEN];
static int		inbufcount = 0;		/* number of chars in inbuf[] */

/*
 * is_input_buf_full(), is_input_buf_empty(), add_to_input_buf(), and
 * trash_input_buf() are functions for manipulating the input buffer.  These
 * are used by the gui_* calls when a GUI is used to handle keyboard input.
 */

	int
is_input_buf_full()
{
	return (inbufcount >= INBUFLEN);
}

	int
is_input_buf_empty()
{
	return (inbufcount == 0);
}

/* Add the given bytes to the input buffer */
	void
add_to_input_buf(s, len)
	char_u	*s;
	int		len;
{
	if (inbufcount + len > INBUFLEN + MAX_KEY_CODE_LEN)
		return;		/* Shouldn't ever happen! */

	while (len--)
		inbuf[inbufcount++] = *s++;
}

/* Remove everything from the input buffer.  Called when ^C is found */
	void
trash_input_buf()
{
	inbufcount = 0;
}

/*
 * Read as much data from the input buffer as possible up to maxlen, and store
 * it in buf.
 * Note: this function used to be Read() in unix.c
 */
	int
read_from_input_buf(buf, maxlen)
	char_u	*buf;
	long	maxlen;
{
	if (inbufcount == 0)		/* if the buffer is empty, fill it */
		fill_input_buf(TRUE);
	if (maxlen > inbufcount)
		maxlen = inbufcount;
	vim_memmove(buf, inbuf, (size_t)maxlen);
	inbufcount -= maxlen;
	if (inbufcount)
		vim_memmove(inbuf, inbuf + maxlen, (size_t)inbufcount);
	return (int)maxlen;
}

	void
fill_input_buf(exit_on_error)
	int	exit_on_error;
{
#if defined(UNIX) || defined(OS2)
	int			len;
	int			try;
	static int	did_read_something = FALSE;
#endif

#ifdef USE_GUI
	if (gui.in_use)
	{
		gui_mch_update();
		return;
	}
#endif
#if defined(UNIX) || defined(OS2)
	if (is_input_buf_full())
		return;
	/*
	 * Fill_input_buf() is only called when we really need a character.
	 * If we can't get any, but there is some in the buffer, just return.
	 * If we can't get any, and there isn't any in the buffer, we give up and
	 * exit Vim.
	 */
	for (try = 0; try < 100; ++try)
	{
		len = read(read_cmd_fd, (char *)inbuf + inbufcount,
											 (size_t)(INBUFLEN - inbufcount));
		if (len > 0)
			break;
		/*
		 * If reading stdin results in an error, continue reading stderr.
		 * This helps when using "foo | xargs vim".
		 */
		if (!did_read_something && !isatty(read_cmd_fd) && read_cmd_fd == 0)
			read_cmd_fd = 2;
		if (!exit_on_error)
			return;
	}
	if (len <= 0)
	{
		windgoto((int)Rows - 1, 0);
		fprintf(stderr, "Vim: Error reading input, exiting...\n");
		ml_sync_all(FALSE, TRUE);		/* preserve all swap files */
		getout(1);
	}
	did_read_something = TRUE;
	while (len-- > 0)
	{
		/*
		 * if a CTRL-C was typed, remove it from the buffer and set got_int
		 */
		if (inbuf[inbufcount] == 3)
		{
			/* remove everything typed before the CTRL-C */
			vim_memmove(inbuf, inbuf + inbufcount, (size_t)(len + 1));
			inbufcount = 0;
			got_int = TRUE;
		}
		++inbufcount;
	}
#endif /* UNIX  or OS2 */
}
#endif /* defined(UNIX) || defined(USE_GUI) || defined(OS2) */

These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.