You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

readline.c 7.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324
  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. FILE_LICENCE ( GPL2_OR_LATER );
  19. #include <stdio.h>
  20. #include <string.h>
  21. #include <stdlib.h>
  22. #include <ipxe/console.h>
  23. #include <ipxe/keys.h>
  24. #include <ipxe/editstring.h>
  25. #include <readline/readline.h>
  26. /** @file
  27. *
  28. * Minimal readline
  29. *
  30. */
  31. #define READLINE_MAX 256
  32. /**
  33. * Synchronise console with edited string
  34. *
  35. * @v string Editable string
  36. */
  37. static void sync_console ( struct edit_string *string ) {
  38. unsigned int mod_start = string->mod_start;
  39. unsigned int mod_end = string->mod_end;
  40. unsigned int cursor = string->last_cursor;
  41. size_t len = strlen ( string->buf );
  42. /* Expand region back to old cursor position if applicable */
  43. if ( mod_start > string->last_cursor )
  44. mod_start = string->last_cursor;
  45. /* Expand region forward to new cursor position if applicable */
  46. if ( mod_end < string->cursor )
  47. mod_end = string->cursor;
  48. /* Backspace to start of region */
  49. while ( cursor > mod_start ) {
  50. putchar ( '\b' );
  51. cursor--;
  52. }
  53. /* Print modified region */
  54. while ( cursor < mod_end ) {
  55. putchar ( ( cursor >= len ) ? ' ' : string->buf[cursor] );
  56. cursor++;
  57. }
  58. /* Backspace to new cursor position */
  59. while ( cursor > string->cursor ) {
  60. putchar ( '\b' );
  61. cursor--;
  62. }
  63. }
  64. /**
  65. * Locate history entry
  66. *
  67. * @v history History buffer
  68. * @v depth Depth within history buffer
  69. * @ret entry History entry
  70. */
  71. static struct readline_history_entry *
  72. history_entry ( struct readline_history *history, unsigned int depth ) {
  73. unsigned int offset;
  74. offset = ( ( history->next - depth ) %
  75. ( sizeof ( history->entries ) /
  76. sizeof ( history->entries[0] ) ) );
  77. return &history->entries[offset];
  78. }
  79. /**
  80. * Read string from history buffer
  81. *
  82. * @v history History buffer
  83. * @v depth Depth within history buffer
  84. * @ret string String
  85. */
  86. static const char * history_fetch ( struct readline_history *history,
  87. unsigned int depth ) {
  88. struct readline_history_entry *entry;
  89. /* Return the temporary copy if it exists, otherwise return
  90. * the persistent copy.
  91. */
  92. entry = history_entry ( history, depth );
  93. return ( entry->temp ? entry->temp : entry->string );
  94. }
  95. /**
  96. * Write temporary string copy to history buffer
  97. *
  98. * @v history History buffer
  99. * @v depth Depth within history buffer
  100. * @v string String
  101. */
  102. static void history_store ( struct readline_history *history,
  103. unsigned int depth, const char *string ) {
  104. struct readline_history_entry *entry;
  105. char *temp;
  106. /* Create temporary copy of string */
  107. temp = strdup ( string );
  108. if ( ! temp ) {
  109. /* Just discard the string; there's nothing we can do */
  110. DBGC ( history, "READLINE %p could not store string\n",
  111. history );
  112. return;
  113. }
  114. /* Store temporary copy */
  115. entry = history_entry ( history, depth );
  116. free ( entry->temp );
  117. entry->temp = temp;
  118. }
  119. /**
  120. * Move to new history depth
  121. *
  122. * @v history History buffer
  123. * @v offset Offset by which to change depth
  124. * @v old_string String (possibly modified) at current depth
  125. * @ret new_string String at new depth, or NULL for no movement
  126. */
  127. static const char * history_move ( struct readline_history *history,
  128. int offset, const char *old_string ) {
  129. unsigned int new_depth = ( history->depth + offset );
  130. const char * new_string = history_fetch ( history, new_depth );
  131. /* Depth checks */
  132. if ( new_depth > READLINE_HISTORY_MAX_DEPTH )
  133. return NULL;
  134. if ( ! new_string )
  135. return NULL;
  136. /* Store temporary copy of old string at current depth */
  137. history_store ( history, history->depth, old_string );
  138. /* Update depth */
  139. history->depth = new_depth;
  140. /* Return new string */
  141. return new_string;
  142. }
  143. /**
  144. * Append new history entry
  145. *
  146. * @v history History buffer
  147. * @v string String
  148. */
  149. static void history_append ( struct readline_history *history,
  150. const char *string ) {
  151. struct readline_history_entry *entry;
  152. /* Store new entry */
  153. entry = history_entry ( history, 0 );
  154. assert ( entry->string == NULL );
  155. entry->string = strdup ( string );
  156. if ( ! entry->string ) {
  157. /* Just discard the string; there's nothing we can do */
  158. DBGC ( history, "READLINE %p could not append string\n",
  159. history );
  160. return;
  161. }
  162. /* Increment history position */
  163. history->next++;
  164. /* Prepare empty "next" slot */
  165. entry = history_entry ( history, 0 );
  166. free ( entry->string );
  167. entry->string = NULL;
  168. }
  169. /**
  170. * Clean up history after editing
  171. *
  172. * @v history History buffer
  173. */
  174. static void history_cleanup ( struct readline_history *history ) {
  175. struct readline_history_entry *entry;
  176. unsigned int i;
  177. /* Discard any temporary strings */
  178. for ( i = 0 ; i < ( sizeof ( history->entries ) /
  179. sizeof ( history->entries[0] ) ) ; i++ ) {
  180. entry = &history->entries[i];
  181. free ( entry->temp );
  182. entry->temp = NULL;
  183. }
  184. /* Reset depth */
  185. history->depth = 0;
  186. /* Sanity check */
  187. entry = history_entry ( history, 0 );
  188. assert ( entry->string == NULL );
  189. }
  190. /**
  191. * Free history buffer
  192. *
  193. * @v history History buffer
  194. */
  195. void history_free ( struct readline_history *history ) {
  196. struct readline_history_entry *entry;
  197. unsigned int i;
  198. /* Discard any temporary strings */
  199. for ( i = 0 ; i < ( sizeof ( history->entries ) /
  200. sizeof ( history->entries[0] ) ) ; i++ ) {
  201. entry = &history->entries[i];
  202. assert ( entry->temp == NULL );
  203. free ( entry->string );
  204. }
  205. }
  206. /**
  207. * Read line from console (with history)
  208. *
  209. * @v prompt Prompt string
  210. * @v history History buffer, or NULL for no history
  211. * @ret line Line read from console (excluding terminating newline)
  212. *
  213. * The returned line is allocated with malloc(); the caller must
  214. * eventually call free() to release the storage.
  215. */
  216. char * readline_history ( const char *prompt,
  217. struct readline_history *history ) {
  218. char buf[READLINE_MAX];
  219. struct edit_string string;
  220. int key;
  221. int move_by;
  222. const char *new_string;
  223. char *line;
  224. /* Display prompt, if applicable */
  225. if ( prompt )
  226. printf ( "%s", prompt );
  227. /* Initialise editable string */
  228. memset ( &string, 0, sizeof ( string ) );
  229. init_editstring ( &string, buf, sizeof ( buf ) );
  230. buf[0] = '\0';
  231. while ( 1 ) {
  232. /* Handle keypress */
  233. key = edit_string ( &string, getkey ( 0 ) );
  234. sync_console ( &string );
  235. move_by = 0;
  236. switch ( key ) {
  237. case CR:
  238. case LF:
  239. line = strdup ( buf );
  240. if ( ! line )
  241. printf ( "\nOut of memory" );
  242. goto done;
  243. case CTRL_C:
  244. line = NULL;
  245. goto done;
  246. case KEY_UP:
  247. move_by = 1;
  248. break;
  249. case KEY_DOWN:
  250. move_by = -1;
  251. break;
  252. default:
  253. /* Do nothing */
  254. break;
  255. }
  256. /* Handle history movement, if applicable */
  257. if ( move_by && history ) {
  258. new_string = history_move ( history, move_by, buf );
  259. if ( new_string ) {
  260. replace_string ( &string, new_string );
  261. sync_console ( &string );
  262. }
  263. }
  264. }
  265. done:
  266. putchar ( '\n' );
  267. if ( history ) {
  268. if ( line && line[0] )
  269. history_append ( history, line );
  270. history_cleanup ( history );
  271. }
  272. return line;
  273. }
  274. /**
  275. * Read line from console
  276. *
  277. * @v prompt Prompt string
  278. * @ret line Line read from console (excluding terminating newline)
  279. *
  280. * The returned line is allocated with malloc(); the caller must
  281. * eventually call free() to release the storage.
  282. */
  283. char * readline ( const char *prompt ) {
  284. return readline_history ( prompt, NULL );
  285. }