ftp.nice.ch/pub/next/unix/editor/ne-1.0.NI.s.tar.gz#/ne-1.0.NI.s/src/input.c

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

/* Input line handling.

   Copyright (C) 1993 Sebastiano Vigna

    This file is part of ne, the nice editor.

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2, or (at your option)
    any later version.

    This program 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 General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

In other words, you are welcome to use, share and improve this program.
You are forbidden to forbid anyone else to use, share and improve
what you give them.   Help stamp out software-hoarding!  */


#include "ne.h"
#include "termchar.h"


/* This is the maximum number of characters which can be typed on the input line. */

#define MAX_INPUT_LINE_LEN		1024



/* This function prints an input prompt in the input line. A colon is
postpended to the prompt. The position of the first character to use for
input is returned. Moreover, the status bar is reset, so that it will be
updated. */


static unsigned int print_prompt(const char *prompt) {

	assert(prompt != NULL);

	move_cursor(lines-1, 0);

	clear_to_eol();

	standout_on();

	output_string(prompt);
	output_string(":");

	standout_off();

	output_chars(NULL, 1);

	reset_status_bar();

	return(strlen(prompt)+2);
}



/* This function prompts the user for a yes/no answer. default_value has to
be TRUE or FALSE. TRUE is returned if 'y' was typed, FALSE in any other
case. Escaping is not allowed. RETURN returns the default value. */


int request_response(buffer *b, const char *prompt, int default_value) {

	char response = request_char(b, prompt, default_value ? 'y' : 'n');

	if (response == 'Y') return(TRUE);
	return(FALSE);
}



/* This function prompts the user for a single charancter answer.
default_value has to be a character which is used for the default answer.
The character typed by the user (upper cased) is returned. The default
character is used if the user types RETURN. Note that the cursor is moved
back to its current position. This offers a clear distinction between
immediate and long inputs, and allows for interactive search and replace. */


char request_char(buffer *b, const char *prompt, const char default_value) {

	int c;
	input_class ic;

	print_prompt(prompt);

	if (default_value) output_chars(&default_value, 1);
	move_cursor(b->cur_y, b->cur_x);

	while(TRUE) {
		while((ic = char_class[c = get_key_code()]) == IGNORE);

		switch(ic) {
			case ALPHA:
				return((char)up_case[(unsigned char)c]);

			case RETURN:
				return((char)up_case[(unsigned char)default_value]);

			default:
				break;
		}
	}
}



/* This function requests a number, with a given prompt and default value.
Only nonnegative integers can be entered. The effects of a negative
default_value are mysterious, and not worth an investigation. The returned
value is nonnegative if something was entered, negative on escaping or on
entering the empty string. */


int request_number(const char *prompt, int default_value) {

	char t[MAX_INT_LEN], *result;

	if (default_value >= 0) sprintf(t, "%d", default_value);

	if (!(result = request(prompt, default_value >= 0 ? t : NULL, FALSE)) || !*result) return(ERROR);

	return(atoi(result));
}



/* This function requests a string. The returned string is never longer than
MAX_INPUT_LINE_LEN, and has been malloc()ed, so you can use it and then
free() it. NULL is returned on escaping, or if entering an empty string
(unless accept_null_string is TRUE, in which case the empty string is
duplicated and returned). */

char *request_string(const char *prompt, const char *default_string, int accept_null_string) {

	char *result = request(prompt, default_string, TRUE);

	if (result && (*result || accept_null_string)) return(str_dup(result));

	return(NULL);
}



/* This is the main function which serves request_number() and
request_string(). Given a prompt, a default string and a boolean flag which
establish the possibility of any alphabetical input (as opposed to digits
only), the user can edit a string of at most MAX_INPUT_LINE_LEN characters.
Many useful commands can be used here. The string edited by the user is
returned, or NULL if the input was escaped, or the empty string was entered.
Note that presently this function always returns a pointer to a static
buffer, but this could change in the future.

The function relies on a number of auxiliary functions and static data. As
always, we would really need nested functions, but, alas, C can't cope with
them. */

static char input_buffer[MAX_INPUT_LINE_LEN+1];

/* start_x os the first usable x position for editing; len is the current
length of the input buffer; x is the x position of the cursor; pos the
position of the cursor inside the input buffer; offset is always pos-(x-start_x). */

static int start_x, len, pos, x, offset;


/* The following functions are rather intuitive. The perform basic editing
actions on the input line. */


static void input_refresh(void) {
	int i;

	move_cursor(lines-1, start_x);
	for(i=0; i<columns-1-start_x && i+offset<len; i++) output_chars(&input_buffer[i+offset], 1);
	clear_to_eol();
}


static void input_move_left(void) {
	if (pos>0) {

		pos--;
		x--;

		if (x < start_x) {
			x++;
			offset--;
			if (char_ins_del_ok) {
				move_cursor(lines-1, columns-2);
				delete_chars(1);
				move_cursor(lines-1, start_x);
				insert_chars(&input_buffer[pos], 1);
			}
			else input_refresh();
		}
	}
}


static void input_move_right(void) {
	if (pos<len) {
		pos++;
		x++;

		if (x == columns-1) {
			x--;
			offset++;

			if (char_ins_del_ok) {
				move_cursor(lines-1, start_x);
				delete_chars(1);
				move_cursor(lines-1, columns-2);
				if (pos < len) output_chars(&input_buffer[pos], 1);
			}
			else input_refresh();
		}
	}
}


static void input_move_to_sol(void) {

	if (offset == 0) {
		x = start_x;
		pos = 0;
		return;
	}

	x = start_x;
	offset = pos = 0;
	input_refresh();
}


static void input_move_to_eol(void) {

	if (x+(len-pos) < columns-1) {
		x += len-pos;
		pos = len;
		return;
	}

	x = columns-2;
	pos = len;
	offset = len-(columns-2-start_x);
	input_refresh();
}


static void input_next_word(void) {

	int space_skipped = FALSE;

	while(pos<len) {
		if (isspace(input_buffer[pos]) || ispunct(input_buffer[pos])) space_skipped = TRUE;
		else if (space_skipped) break;
		input_move_right();
	}
}


static void input_prev_word(void) {

	int word_skipped = FALSE;

	while(pos > 0) {
		if (!(isspace(input_buffer[pos-1]) || ispunct(input_buffer[pos-1]))) word_skipped = TRUE;
		else if (word_skipped) break;
		input_move_left();
	}
}


static void input_paste(void) {

	clip_desc *cd = get_nth_clip(cur_buffer->cur_clip);

	if (cd) {
		strncpy(input_buffer, cd->cs->stream, MAX_INPUT_LINE_LEN);

		len = strlen(input_buffer);
		pos = offset = 0;
		x = start_x;
		input_refresh();
	}
}


char *request(const char *prompt, const char *default_string, int alpha_allowed) {

	action a;
	input_class ic;
	int c, first_char_typed = TRUE;

	pos = len = offset = 0;
	x = start_x = print_prompt(prompt);

	if (default_string) {
		strncpy(input_buffer, default_string, MAX_INPUT_LINE_LEN);
		len = strlen(input_buffer);
		input_refresh();
	}

	while(TRUE) {

		move_cursor(lines-1, x);

		while((ic = char_class[c = get_key_code()]) == IGNORE);

		switch(ic) {
			case ALPHA:

				if (first_char_typed) {
					len = 0;
					clear_to_eol();
				}

				if (len<MAX_INPUT_LINE_LEN && (alpha_allowed || c>='0' && c<='9')) {

					memmove(&input_buffer[pos+1], &input_buffer[pos], len-pos);
					input_buffer[pos] = c;
					len++;

					move_cursor(lines-1, x);

					if (x < columns-2) {
						if (pos == len-1) output_chars(input_buffer+pos, 1);
						else if (char_ins_del_ok) insert_chars(input_buffer+pos, 1);
						else input_refresh();
					}
					else output_chars(input_buffer+pos, 1);

					input_move_right();
				}
				break;

			case RETURN:
				input_buffer[len] = 0;
				return(input_buffer);

			case COMMAND:
				if ((a = parse_command_line(key_binding[c], NULL, NULL, FALSE))>=0) {
					switch(a) {

						case MOVE_LEFT:
							input_move_left();
							break;

						case MOVE_RIGHT:
							input_move_right();
							break;

						case BACKSPACE:
							if (pos == 0) break;
							input_move_left();

						case DELETE_CHAR:
							if (len>0 && pos<len) {

								memmove(&input_buffer[pos], &input_buffer[pos+1], len-pos-1);
								len--;

								if (char_ins_del_ok) {
									move_cursor(lines-1, x);
									delete_chars(1);

									if (pos+(columns-2-x) < len) {
										move_cursor(lines-1, columns-2);
										output_chars(&input_buffer[pos+(columns-2-x)], 1);
									}
								}
								else input_refresh();
							}
							break;

						case DELETE_LINE:
							move_cursor(lines-1, start_x);
							clear_to_eol();
							len = pos = offset = 0;
							x = start_x;
							break;

						case DELETE_TO_EOL:
							len = pos;
							clear_to_eol();
							break;

						case MOVE_TO_SOL:
						case MOVE_TO_SOF:
							input_move_to_sol();
							break;

						case MOVE_TO_EOL:
						case MOVE_TO_EOF:
							input_move_to_eol();
							break;

						case TOGGLE_SOL_EOL:
						case TOGGLE_SOF_EOF:
							if (pos != 0) input_move_to_sol();
							else input_move_to_eol();
							break;

						case PREV_WORD:
							input_prev_word();
							break;

						case NEXT_WORD:
							input_next_word();
							break;

						case REFRESH:
							input_refresh();
							break;

						case PASTE:
							input_paste();
							break;

						case ESCAPE:
							return(NULL);
					}
				}
				break;

			default:
				break;
		}

		first_char_typed = FALSE;
	}
}



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