Re-enable spec/library for full CI runs.
[rbx.git] / lib / ext / readline / readline.c
blobc74090b01cb43630402ca4ed085d1026ef9a7430
1 /* readline.c -- GNU Readline module
2 Copyright (C) 1997-2001 Shugo Maeda */
4 #include <errno.h>
5 #include <stdio.h>
6 #include <ctype.h>
7 #include <string.h>
8 #include <readline/readline.h>
9 #include <readline/history.h>
11 #include "ruby.h"
13 #include <unistd.h>
15 static VALUE mReadline;
17 #define TOLOWER(c) (isupper(c) ? tolower(c) : c)
19 #define COMPLETION_PROC "completion_proc"
20 #define COMPLETION_CASE_FOLD "completion_case_fold"
21 static ID completion_proc, completion_case_fold;
23 static int readline_event(void);
24 static char **readline_attempted_completion_function(const char *text,
25 int start, int end);
27 static int
28 readline_event()
30 CHECK_INTS;
31 rb_thread_schedule();
32 return 0;
35 static VALUE
36 readline_readline(VALUE self, VALUE tmp, VALUE add_hist)
38 VALUE result;
39 char *prompt = NULL;
40 char *buff;
41 int status;
43 rb_secure(4);
44 SafeStringValue(tmp);
45 prompt = rb_str_get_char_ptr(tmp);
47 if (!isatty(0) && errno == EBADF) rb_raise(rb_eIOError, "stdin closed");
49 buff = readline(prompt);
51 #if 0
52 buff = (char*)rb_protect((VALUE(*)_((VALUE)))readline, (VALUE)prompt,
53 &status);
54 if (status) {
55 #if defined HAVE_RL_CLEANUP_AFTER_SIGNAL
56 /* restore terminal mode and signal handler*/
57 rl_cleanup_after_signal();
58 #elif defined HAVE_RL_DEPREP_TERM_FUNCTION
59 /* restore terminal mode */
60 (*rl_deprep_term_function)();
61 #else
62 rl_deprep_terminal();
63 #endif
64 rb_jump_tag(status);
66 #endif
68 if (RTEST(add_hist) && buff) {
69 add_history(buff);
72 if (buff) {
73 result = rb_tainted_str_new2(buff);
74 free(buff);
75 } else {
76 result = Qnil;
79 return result;
82 static VALUE
83 readline_s_set_completion_proc(self, proc)
84 VALUE self;
85 VALUE proc;
87 rb_secure(4);
88 if (!rb_respond_to(proc, rb_intern("call")))
89 rb_raise(rb_eArgError, "argument must respond to `call'");
90 return rb_ivar_set(mReadline, completion_proc, proc);
93 static VALUE
94 readline_s_get_completion_proc(self)
95 VALUE self;
97 rb_secure(4);
98 return rb_attr_get(mReadline, completion_proc);
101 static VALUE
102 readline_s_set_completion_case_fold(self, val)
103 VALUE self;
104 VALUE val;
106 rb_secure(4);
107 return rb_ivar_set(mReadline, completion_case_fold, val);
110 static VALUE
111 readline_s_get_completion_case_fold(self)
112 VALUE self;
114 rb_secure(4);
115 return rb_attr_get(mReadline, completion_case_fold);
118 static char **
119 readline_attempted_completion_function(text, start, end)
120 const char *text;
121 int start;
122 int end;
124 VALUE proc, ary, temp;
125 char **result;
126 int case_fold;
127 int i, matches;
129 proc = rb_attr_get(mReadline, completion_proc);
130 if (NIL_P(proc))
131 return NULL;
132 #ifdef HAVE_RL_ATTEMPTED_COMPLETION_OVER
133 rl_attempted_completion_over = 1;
134 #endif
135 case_fold = RTEST(rb_attr_get(mReadline, completion_case_fold));
136 ary = rb_funcall(proc, rb_intern("call"), 1, rb_tainted_str_new2(text));
137 ary = rb_Array(ary);
139 matches = rb_ary_size(ary);
140 if (matches == 0) return NULL;
141 result = ALLOC_N(char *, matches + 2);
142 for (i = 0; i < matches; i++) {
143 temp = rb_obj_as_string(rb_ary_entry(ary, i));
144 result[i + 1] = rb_str_get_char_ptr(temp);
146 result[matches + 1] = NULL;
148 if (matches == 1) {
149 result[0] = strdup(result[1]);
151 else {
152 register int i = 1;
153 int low = 100000;
155 while (i < matches) {
156 register int c1, c2, si;
158 if (case_fold) {
159 for (si = 0;
160 (c1 = TOLOWER(result[i][si])) &&
161 (c2 = TOLOWER(result[i + 1][si]));
162 si++)
163 if (c1 != c2) break;
164 } else {
165 for (si = 0;
166 (c1 = result[i][si]) &&
167 (c2 = result[i + 1][si]);
168 si++)
169 if (c1 != c2) break;
172 if (low > si) low = si;
173 i++;
175 result[0] = ALLOC_N(char, low + 1);
176 strncpy(result[0], result[1], low);
177 result[0][low] = '\0';
180 return result;
183 static VALUE
184 readline_s_set_completion_append_character(self, str)
185 VALUE self, str;
187 rb_secure(4);
188 if (NIL_P(str)) {
189 rl_completion_append_character = '\0';
191 else {
192 SafeStringValue(str);
193 if (rb_str_get_char_len(str) == 0) {
194 rl_completion_append_character = '\0';
195 } else {
196 rl_completion_append_character = rb_str_get_char(str, 0);
199 return self;
202 static VALUE
203 readline_s_get_completion_append_character(self)
204 VALUE self;
206 VALUE str;
208 rb_secure(4);
209 if (rl_completion_append_character == '\0')
210 return Qnil;
212 return rb_str_new((char*)&rl_completion_append_character, 1);
215 static VALUE
216 readline_s_set_basic_word_break_characters(self, str)
217 VALUE self, str;
220 rb_secure(4);
221 SafeStringValue(str);
223 rl_basic_word_break_characters = rb_str_get_char_ptr(str);
225 return self;
228 static VALUE
229 readline_s_get_basic_word_break_characters(self, str)
230 VALUE self, str;
232 rb_secure(4);
233 if (rl_basic_word_break_characters == NULL)
234 return Qnil;
235 return rb_tainted_str_new2(rl_basic_word_break_characters);
238 static VALUE
239 readline_s_set_completer_word_break_characters(self, str)
240 VALUE self, str;
242 rb_secure(4);
243 SafeStringValue(str);
245 rl_completer_word_break_characters = rb_str_get_char_ptr(str);
247 return self;
250 static VALUE
251 readline_s_get_completer_word_break_characters(self, str)
252 VALUE self, str;
254 rb_secure(4);
255 if (rl_completer_word_break_characters == NULL)
256 return Qnil;
257 return rb_tainted_str_new2(rl_completer_word_break_characters);
260 static VALUE
261 readline_s_set_completer_quote_characters(self, str)
262 VALUE self, str;
264 static char *completer_quote_characters = NULL;
266 rb_secure(4);
267 SafeStringValue(str);
269 rl_completer_quote_characters = rb_str_get_char_ptr(str);
271 return self;
274 static VALUE
275 readline_s_get_completer_quote_characters(self, str)
276 VALUE self, str;
278 rb_secure(4);
279 if (rl_completer_quote_characters == NULL)
280 return Qnil;
281 return rb_tainted_str_new2(rl_completer_quote_characters);
284 static VALUE
285 hist_to_s(self)
286 VALUE self;
288 return rb_str_new2("HISTORY");
291 static VALUE
292 hist_get(self, index)
293 VALUE self;
294 VALUE index;
296 HIST_ENTRY *entry;
297 int i;
299 rb_secure(4);
300 i = NUM2INT(index);
301 if (i < 0) {
302 i += history_length;
304 entry = history_get(history_base + i);
305 if (entry == NULL) {
306 rb_raise(rb_eIndexError, "invalid index");
308 return rb_tainted_str_new2(entry->line);
311 static VALUE
312 hist_set(self, index, str)
313 VALUE self;
314 VALUE index;
315 VALUE str;
317 HIST_ENTRY *entry;
318 int i;
319 char *data;
321 rb_secure(4);
322 i = NUM2INT(index);
323 SafeStringValue(str);
324 if (i < 0) {
325 i += history_length;
327 data = rb_str_get_char_ptr(str);
328 entry = replace_history_entry(i, data, NULL);
329 free(data);
330 if (entry == NULL) {
331 rb_raise(rb_eIndexError, "invalid index");
333 return str;
336 static VALUE
337 hist_push(self, str)
338 VALUE self;
339 VALUE str;
341 char *data;
342 rb_secure(4);
343 SafeStringValue(str);
344 data = rb_str_get_char_ptr(str);
345 add_history(data);
346 free(data);
347 return self;
350 static VALUE
351 hist_push_method(argc, argv, self)
352 int argc;
353 VALUE *argv;
354 VALUE self;
356 VALUE str;
357 char *data;
359 rb_secure(4);
360 while (argc--) {
361 str = *argv++;
362 SafeStringValue(str);
363 data = rb_str_get_char_ptr(str);
364 add_history(data);
365 free(data);
367 return self;
370 static VALUE
371 rb_remove_history(index)
372 int index;
374 HIST_ENTRY *entry;
375 VALUE val;
377 rb_secure(4);
378 entry = remove_history(index);
379 if (entry) {
380 val = rb_tainted_str_new2(entry->line);
381 free((char*)entry->line);
382 free(entry);
383 return val;
385 return Qnil;
388 static VALUE
389 hist_pop(self)
390 VALUE self;
392 rb_secure(4);
393 if (history_length > 0) {
394 return rb_remove_history(history_length - 1);
395 } else {
396 return Qnil;
400 static VALUE
401 hist_shift(self)
402 VALUE self;
404 rb_secure(4);
405 if (history_length > 0) {
406 return rb_remove_history(0);
407 } else {
408 return Qnil;
412 static VALUE
413 hist_each(self)
414 VALUE self;
416 HIST_ENTRY *entry;
417 int i;
419 rb_secure(4);
420 for (i = 0; i < history_length; i++) {
421 entry = history_get(history_base + i);
422 if (entry == NULL)
423 break;
424 rb_yield(rb_tainted_str_new2(entry->line));
426 return self;
429 static VALUE
430 hist_length(self)
431 VALUE self;
433 rb_secure(4);
434 return INT2NUM(history_length);
437 static VALUE
438 hist_empty_p(self)
439 VALUE self;
441 rb_secure(4);
442 return history_length == 0 ? Qtrue : Qfalse;
445 static VALUE
446 hist_delete_at(self, index)
447 VALUE self;
448 VALUE index;
450 int i;
452 rb_secure(4);
453 i = NUM2INT(index);
454 if (i < 0)
455 i += history_length;
456 if (i < 0 || i > history_length - 1) {
457 rb_raise(rb_eIndexError, "invalid index");
459 return rb_remove_history(i);
462 void
463 Init_readline()
465 VALUE history, fcomp, ucomp;
467 /* Allow conditional parsing of the ~/.inputrc file. */
468 rl_readline_name = "Ruby";
470 using_history();
472 completion_proc = rb_intern(COMPLETION_PROC);
473 completion_case_fold = rb_intern(COMPLETION_CASE_FOLD);
475 mReadline = rb_define_module("Readline");
476 rb_define_singleton_method(mReadline, "perform_readline",
477 readline_readline, 2);
478 rb_define_singleton_method(mReadline, "completion_proc=",
479 readline_s_set_completion_proc, 1);
480 rb_define_singleton_method(mReadline, "completion_proc",
481 readline_s_get_completion_proc, 0);
482 rb_define_singleton_method(mReadline, "completion_case_fold=",
483 readline_s_set_completion_case_fold, 1);
484 rb_define_singleton_method(mReadline, "completion_case_fold",
485 readline_s_get_completion_case_fold, 0);
486 rb_define_singleton_method(mReadline, "completion_append_character=",
487 readline_s_set_completion_append_character, 1);
488 rb_define_singleton_method(mReadline, "completion_append_character",
489 readline_s_get_completion_append_character, 0);
490 rb_define_singleton_method(mReadline, "basic_word_break_characters=",
491 readline_s_set_basic_word_break_characters, 1);
492 rb_define_singleton_method(mReadline, "basic_word_break_characters",
493 readline_s_get_basic_word_break_characters, 0);
494 rb_define_singleton_method(mReadline, "completer_word_break_characters=",
495 readline_s_set_completer_word_break_characters, 1);
496 rb_define_singleton_method(mReadline, "completer_word_break_characters",
497 readline_s_get_completer_word_break_characters, 0);
498 rb_define_singleton_method(mReadline, "completer_quote_characters=",
499 readline_s_set_completer_quote_characters, 1);
500 rb_define_singleton_method(mReadline, "completer_quote_characters",
501 readline_s_get_completer_quote_characters, 0);
503 history = rb_obj_alloc(rb_cObject);
504 rb_define_singleton_method(history,"to_s", hist_to_s, 0);
505 rb_define_singleton_method(history,"[]", hist_get, 1);
506 rb_define_singleton_method(history,"[]=", hist_set, 2);
507 rb_define_singleton_method(history,"<<", hist_push, 1);
508 rb_define_singleton_method(history,"push", hist_push_method, -1);
509 rb_define_singleton_method(history,"pop", hist_pop, 0);
510 rb_define_singleton_method(history,"shift", hist_shift, 0);
511 rb_define_singleton_method(history,"each", hist_each, 0);
512 rb_define_singleton_method(history,"length", hist_length, 0);
513 rb_define_singleton_method(history,"size", hist_length, 0);
514 rb_define_singleton_method(history,"empty?", hist_empty_p, 0);
515 rb_define_singleton_method(history,"delete_at", hist_delete_at, 1);
516 rb_define_const(mReadline, "HISTORY", history);
518 rb_define_const(mReadline, "VERSION", rb_str_new2(rl_library_version));
520 rl_attempted_completion_function = readline_attempted_completion_function;