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.