1/* 2 * Copyright (C) 2006 Michael Brown <mbrown@fensystems.co.uk>. 3 * 4 * This program is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU General Public License as 6 * published by the Free Software Foundation; either version 2 of the 7 * License, or any later version. 8 * 9 * This program is distributed in the hope that it will be useful, but 10 * WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 * General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program; if not, write to the Free Software 16 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 17 */ 18 19FILE_LICENCE ( GPL2_OR_LATER ); 20 21#include <assert.h> 22#include <string.h> 23#include <gpxe/keys.h> 24#include <gpxe/editstring.h> 25 26/** @file 27 * 28 * Editable strings 29 * 30 */ 31 32static void insert_delete ( struct edit_string *string, size_t delete_len, 33 const char *insert_text ) 34 __attribute__ (( nonnull (1) )); 35static void insert_character ( struct edit_string *string, 36 unsigned int character ) __nonnull; 37static void delete_character ( struct edit_string *string ) __nonnull; 38static void backspace ( struct edit_string *string ) __nonnull; 39static void kill_eol ( struct edit_string *string ) __nonnull; 40 41/** 42 * Insert and/or delete text within an editable string 43 * 44 * @v string Editable string 45 * @v delete_len Length of text to delete from current cursor position 46 * @v insert_text Text to insert at current cursor position, or NULL 47 */ 48static void insert_delete ( struct edit_string *string, size_t delete_len, 49 const char *insert_text ) { 50 size_t old_len, max_delete_len, insert_len, max_insert_len, new_len; 51 52 /* Calculate lengths */ 53 old_len = strlen ( string->buf ); 54 assert ( string->cursor <= old_len ); 55 max_delete_len = ( old_len - string->cursor ); 56 if ( delete_len > max_delete_len ) 57 delete_len = max_delete_len; 58 insert_len = ( insert_text ? strlen ( insert_text ) : 0 ); 59 max_insert_len = ( ( string->len - 1 ) - ( old_len - delete_len ) ); 60 if ( insert_len > max_insert_len ) 61 insert_len = max_insert_len; 62 new_len = ( old_len - delete_len + insert_len ); 63 64 /* Fill in edit history */ 65 string->mod_start = string->cursor; 66 string->mod_end = ( ( new_len > old_len ) ? new_len : old_len ); 67 68 /* Move data following the cursor */ 69 memmove ( ( string->buf + string->cursor + insert_len ), 70 ( string->buf + string->cursor + delete_len ), 71 ( max_delete_len + 1 - delete_len ) ); 72 73 /* Copy inserted text to cursor position */ 74 memcpy ( ( string->buf + string->cursor ), insert_text, insert_len ); 75 string->cursor += insert_len; 76} 77 78/** 79 * Insert character at current cursor position 80 * 81 * @v string Editable string 82 * @v character Character to insert 83 */ 84static void insert_character ( struct edit_string *string, 85 unsigned int character ) { 86 char insert_text[2] = { character, '\0' }; 87 insert_delete ( string, 0, insert_text ); 88} 89 90/** 91 * Delete character at current cursor position 92 * 93 * @v string Editable string 94 */ 95static void delete_character ( struct edit_string *string ) { 96 insert_delete ( string, 1, NULL ); 97} 98 99/** 100 * Delete character to left of current cursor position 101 * 102 * @v string Editable string 103 */ 104static void backspace ( struct edit_string *string ) { 105 if ( string->cursor > 0 ) { 106 string->cursor--; 107 delete_character ( string ); 108 } 109} 110 111/** 112 * Delete to end of line 113 * 114 * @v string Editable string 115 */ 116static void kill_eol ( struct edit_string *string ) { 117 insert_delete ( string, ~( ( size_t ) 0 ), NULL ); 118} 119 120/** 121 * Edit editable string 122 * 123 * @v string Editable string 124 * @v key Key pressed by user 125 * @ret key Key returned to application, or zero 126 * 127 * Handles keypresses and updates the content of the editable string. 128 * Basic line editing facilities (delete/insert/cursor) are supported. 129 * If edit_string() understands and uses the keypress it will return 130 * zero, otherwise it will return the original key. 131 * 132 * This function does not update the display in any way. 133 * 134 * The string's edit history will be updated to allow the caller to 135 * efficiently bring the display into sync with the string content. 136 */ 137int edit_string ( struct edit_string *string, int key ) { 138 int retval = 0; 139 size_t len = strlen ( string->buf ); 140 141 /* Prepare edit history */ 142 string->last_cursor = string->cursor; 143 string->mod_start = string->cursor; 144 string->mod_end = string->cursor; 145 146 /* Interpret key */ 147 if ( ( key >= 0x20 ) && ( key <= 0x7e ) ) { 148 /* Printable character; insert at current position */ 149 insert_character ( string, key ); 150 } else switch ( key ) { 151 case KEY_BACKSPACE: 152 /* Backspace */ 153 backspace ( string ); 154 break; 155 case KEY_DC: 156 case CTRL_D: 157 /* Delete character */ 158 delete_character ( string ); 159 break; 160 case CTRL_K: 161 /* Delete to end of line */ 162 kill_eol ( string ); 163 break; 164 case KEY_HOME: 165 case CTRL_A: 166 /* Start of line */ 167 string->cursor = 0; 168 break; 169 case KEY_END: 170 case CTRL_E: 171 /* End of line */ 172 string->cursor = len; 173 break; 174 case KEY_LEFT: 175 case CTRL_B: 176 /* Cursor left */ 177 if ( string->cursor > 0 ) 178 string->cursor--; 179 break; 180 case KEY_RIGHT: 181 case CTRL_F: 182 /* Cursor right */ 183 if ( string->cursor < len ) 184 string->cursor++; 185 break; 186 default: 187 retval = key; 188 break; 189 } 190 191 return retval; 192} 193