Project

General

Profile

Bug #212 ยป no212_ext-readline-readline.c.patch

for 1.8 branch. - kouji (Kouji Takao), 08/14/2008 01:38 AM

View differences:

ext/readline/readline.c (working copy)
28 28

  
29 29
#define TOLOWER(c) (isupper(c) ? tolower(c) : c)
30 30

  
31
#define EDIT_LINE_LIBRARY_VERSION "EditLine wrapper"
31 32
#define COMPLETION_PROC "completion_proc"
32 33
#define COMPLETION_CASE_FOLD "completion_case_fold"
33 34
static ID completion_proc, completion_case_fold;
......
42 43
# define rl_completion_matches completion_matches
43 44
#endif
44 45

  
46
static int (*history_get_offset_func)(int);
47

  
45 48
static char **readline_attempted_completion_function(const char *text,
46 49
                                                     int start, int end);
47 50

  
......
518 521
    return rb_str_new2("HISTORY");
519 522
}
520 523

  
524
static int
525
history_get_offset_history_base(offset)
526
    int offset;
527
{
528
    return history_base + offset;
529
}
530

  
531
static int
532
history_get_offset_0(offset)
533
    int offset;
534
{
535
    return offset;
536
}
537

  
521 538
static VALUE
522 539
hist_get(self, index)
523 540
    VALUE self;
524 541
    VALUE index;
525 542
{
526
    HIST_ENTRY *entry;
543
    HIST_ENTRY *entry = NULL;
527 544
    int i;
528 545

  
529 546
    rb_secure(4);
......
531 548
    if (i < 0) {
532 549
        i += history_length;
533 550
    }
534
    entry = history_get(history_base + i);
551
    if (i >= 0) {
552
	entry = history_get(history_get_offset_func(i));
553
    }
535 554
    if (entry == NULL) {
536 555
	rb_raise(rb_eIndexError, "invalid index");
537 556
    }
......
545 564
    VALUE str;
546 565
{
547 566
#ifdef HAVE_REPLACE_HISTORY_ENTRY
548
    HIST_ENTRY *entry;
567
    HIST_ENTRY *entry = NULL;
549 568
    int i;
550 569

  
551 570
    rb_secure(4);
......
554 573
    if (i < 0) {
555 574
        i += history_length;
556 575
    }
557
    entry = replace_history_entry(i, RSTRING(str)->ptr, NULL);
576
    if (i >= 0) {
577
	entry = replace_history_entry(i, RSTRING_PTR(str), NULL);
578
    }
558 579
    if (entry == NULL) {
559 580
	rb_raise(rb_eIndexError, "invalid index");
560 581
    }
......
649 670

  
650 671
    rb_secure(4);
651 672
    for (i = 0; i < history_length; i++) {
652
        entry = history_get(history_base + i);
673
        entry = history_get(history_get_offset_func(i));
653 674
        if (entry == NULL)
654 675
            break;
655 676
	rb_yield(rb_tainted_str_new2(entry->line));
......
691 712
}
692 713

  
693 714
static VALUE
715
hist_clear(self)
716
    VALUE self;
717
{
718
#ifdef HAVE_CLEAR_HISTORY
719
    rb_secure(4);
720
    clear_history();
721
    return self;
722
#else
723
    rb_notimplement();
724
    return Qnil; /* not reached */
725
#endif
726
}
727

  
728
static VALUE
694 729
filename_completion_proc_call(self, str)
695 730
    VALUE self;
696 731
    VALUE str;
......
811 846
    rb_define_singleton_method(history,"size", hist_length, 0);
812 847
    rb_define_singleton_method(history,"empty?", hist_empty_p, 0);
813 848
    rb_define_singleton_method(history,"delete_at", hist_delete_at, 1);
849
    rb_define_singleton_method(history,"clear", hist_clear, 0);
814 850
    rb_define_const(mReadline, "HISTORY", history);
815 851

  
816 852
    fcomp = rb_obj_alloc(rb_cObject);
......
822 858
    rb_define_singleton_method(ucomp, "call",
823 859
			       username_completion_proc_call, 1);
824 860
    rb_define_const(mReadline, "USERNAME_COMPLETION_PROC", ucomp);
861
    history_get_offset_func = history_get_offset_history_base;
825 862
#if defined HAVE_RL_LIBRARY_VERSION
826 863
    rb_define_const(mReadline, "VERSION", rb_str_new2(rl_library_version));
864
#if defined HAVE_CLEAR_HISTORY || defined HAVE_HAVE_REMOVE_HISTORY
865
    if (strncmp(rl_library_version, EDIT_LINE_LIBRARY_VERSION, 
866
		strlen(EDIT_LINE_LIBRARY_VERSION)) == 0) {
867
	add_history("1");
868
	if (history_get(history_get_offset_func(0)) == NULL) {
869
	    history_get_offset_func = history_get_offset_0;
870
	}
871
#if defined HAVE_CLEAR_HISTORY
872
	clear_history();
827 873
#else
874
	{
875
	    HIST_ENTRY *entry = remove_history(0);
876
	    free(entry->line);
877
	    free(entry);
878
	}
879
#endif
880
    }
881
#endif
882
#else
828 883
    rb_define_const(mReadline, "VERSION",
829 884
                    rb_str_new2("2.0 or before version"));
830 885
#endif
ext/readline/extconf.rb (working copy)
65 65
have_readline_func("rl_emacs_editing_mode")
66 66
have_readline_func("replace_history_entry")
67 67
have_readline_func("remove_history")
68
have_readline_func("clear_history")
68 69
create_makefile("readline")
test/readline/test_readline_history.rb (revision 0)
1
begin
2
  require "readline"
3
=begin
4
  class << Readline::HISTORY
5
    def []=(index, str)
6
      raise NotImplementedError
7
    end
8

  
9
    def pop
10
      raise NotImplementedError
11
    end
12

  
13
    def shift
14
      raise NotImplementedError
15
    end
16

  
17
    def delete_at(index)
18
      raise NotImplementedError
19
    end
20
  end
21
=end
22

  
23
=begin
24
  class << Readline::HISTORY
25
    def clear
26
      raise NotImplementedError
27
    end
28
  end
29
=end
30
rescue LoadError
31
else
32
  require "test/unit"
33
end
34

  
35
class Readline::TestHistory < Test::Unit::TestCase
36
  include Readline
37

  
38
  def setup
39
    HISTORY.clear
40
  end
41

  
42
  def test_safe_level_4
43
    method_args =
44
      [
45
       ["[]", [0]],
46
       ["[]=", [0, "s"]],
47
       ["\<\<", ["s"]],
48
       ["push", ["s"]],
49
       ["pop", []],
50
       ["shift", []],
51
       ["length", []],
52
       ["delete_at", [0]],
53
       ["clear", []],
54
      ]
55
    method_args.each do |method_name, args|
56
      assert_raises(SecurityError, NotImplementedError,
57
                    "method=<#{method_name}>") do
58
        Thread.start {
59
          $SAFE = 4
60
          HISTORY.send(method_name.to_sym, *args)
61
          assert(true)
62
        }.join
63
      end
64
    end
65

  
66
    assert_raises(SecurityError, NotImplementedError,
67
                  "method=<each>") do
68
      Thread.start {
69
        $SAFE = 4
70
        HISTORY.each { |s|
71
          assert(true)
72
        }
73
      }.join
74
    end
75
  end
76
  
77
  def test_to_s
78
    assert_equal("HISTORY", HISTORY.to_s)
79
  end
80

  
81
  def test_get
82
    lines = push_history(5)
83
    lines.each_with_index do |s, i|
84
      assert_equal(s, HISTORY[i])
85
    end
86
  end
87

  
88
  def test_get__negative
89
    lines = push_history(5)
90
    (1..5).each do |i|
91
      assert_equal(lines[-i], HISTORY[-i])
92
    end
93
  end
94

  
95
  def test_get__out_of_range
96
    lines = push_history(5)
97
    invalid_indexes = [5, 6, 100, -6, -7, -100]
98
    invalid_indexes.each do |i|
99
      assert_raise(IndexError, "i=<#{i}>") do
100
        HISTORY[i]
101
      end
102
    end
103
    
104
    invalid_indexes = [100_000_000_000_000_000_000,
105
                       -100_000_000_000_000_000_000]
106
    invalid_indexes.each do |i|
107
      assert_raise(RangeError, "i=<#{i}>") do
108
        HISTORY[i]
109
      end
110
    end
111
  end
112

  
113
  def test_set
114
    begin
115
      lines = push_history(5)
116
      5.times do |i|
117
        expected = "set: #{i}"
118
        HISTORY[i] = expected
119
        assert_equal(expected, HISTORY[i])
120
      end
121
    rescue NotImplementedError
122
    end
123
  end
124

  
125
  def test_set__out_of_range
126
    assert_raises(IndexError, NotImplementedError, "index=<0>") do
127
      HISTORY[0] = "set: 0"
128
    end
129
    
130
    lines = push_history(5)
131
    invalid_indexes = [5, 6, 100, -6, -7, -100]
132
    invalid_indexes.each do |i|
133
      assert_raises(IndexError, NotImplementedError, "index=<#{i}>") do
134
        HISTORY[i] = "set: #{i}"
135
      end
136
    end
137
    
138
    invalid_indexes = [100_000_000_000_000_000_000,
139
                       -100_000_000_000_000_000_000]
140
    invalid_indexes.each do |i|
141
      assert_raise(RangeError, NotImplementedError, "index=<#{i}>") do
142
        HISTORY[i] = "set: #{i}"
143
      end
144
    end
145
  end
146

  
147
  def test_push
148
    5.times do |i|
149
      assert_equal(HISTORY, HISTORY.push(i.to_s))
150
      assert_equal(i.to_s, HISTORY[i])
151
    end
152
    assert_equal(5, HISTORY.length)
153
  end
154

  
155
  def test_push__operator
156
    5.times do |i|
157
      assert_equal(HISTORY, HISTORY << i.to_s)
158
      assert_equal(i.to_s, HISTORY[i])
159
    end
160
    assert_equal(5, HISTORY.length)
161
  end
162

  
163
  def test_push__plural
164
    assert_equal(HISTORY, HISTORY.push("0", "1", "2", "3", "4"))
165
    (0..4).each do |i|
166
      assert_equal(i.to_s, HISTORY[i])
167
    end
168
    assert_equal(5, HISTORY.length)
169

  
170
    assert_equal(HISTORY, HISTORY.push("5", "6", "7", "8", "9"))
171
    (5..9).each do |i|
172
      assert_equal(i.to_s, HISTORY[i])
173
    end
174
    assert_equal(10, HISTORY.length)
175
  end
176

  
177
  def test_pop
178
    begin
179
      assert_equal(nil, HISTORY.pop)
180
      
181
      lines = push_history(5)
182
      (1..5).each do |i|
183
        assert_equal(lines[-i], HISTORY.pop)
184
        assert_equal(lines.length - i, HISTORY.length)
185
      end
186
      
187
      assert_equal(nil, HISTORY.pop)
188
    rescue NotImplementedError
189
    end
190
  end
191

  
192
  def test_shift
193
    begin
194
      assert_equal(nil, HISTORY.shift)
195
      
196
      lines = push_history(5)
197
      (0..4).each do |i|
198
        assert_equal(lines[i], HISTORY.shift)
199
        assert_equal(lines.length - (i + 1), HISTORY.length)
200
      end
201
    
202
      assert_equal(nil, HISTORY.shift)
203
    rescue NotImplementedError
204
    end
205
  end
206

  
207
  def test_each
208
    HISTORY.each do |s|
209
      assert(false) # not reachable
210
    end
211
    lines = push_history(5)
212
    i = 0
213
    e = HISTORY.each { |s|
214
      assert_equal(HISTORY[i], s)
215
      assert_equal(lines[i], s)
216
      i += 1
217
    }
218
    assert_equal(HISTORY, e)
219
  end
220

  
221
  def test_length
222
    assert_equal(0, HISTORY.length)
223
    push_history(1)
224
    assert_equal(1, HISTORY.length)
225
    push_history(4)
226
    assert_equal(5, HISTORY.length)
227
    HISTORY.clear
228
    assert_equal(0, HISTORY.length)
229
  end
230

  
231
  def test_empty_p
232
    2.times do
233
      assert(HISTORY.empty?)
234
      HISTORY.push("s")
235
      assert_equal(false, HISTORY.empty?)
236
      HISTORY.clear
237
      assert(HISTORY.empty?)
238
    end
239
  end
240

  
241
  def test_delete_at
242
    begin
243
      lines = push_history(5)
244
      (0..4).each do |i|
245
        assert_equal(lines[i], HISTORY.delete_at(0))
246
      end
247
      assert(HISTORY.empty?)
248

  
249
      lines = push_history(5)
250
      (1..5).each do |i|
251
        assert_equal(lines[lines.length - i], HISTORY.delete_at(-1))
252
      end
253
      assert(HISTORY.empty?)
254

  
255
      lines = push_history(5)
256
      assert_equal(lines[0], HISTORY.delete_at(0))
257
      assert_equal(lines[4], HISTORY.delete_at(3))
258
      assert_equal(lines[1], HISTORY.delete_at(0))
259
      assert_equal(lines[3], HISTORY.delete_at(1))
260
      assert_equal(lines[2], HISTORY.delete_at(0))
261
      assert(HISTORY.empty?)
262
    rescue NotImplementedError
263
    end
264
  end
265

  
266
  def test_delete_at__out_of_range
267
    assert_raises(IndexError, NotImplementedError, "index=<0>") do
268
      HISTORY.delete_at(0)
269
    end
270
      
271
    lines = push_history(5)
272
    invalid_indexes = [5, 6, 100, -6, -7, -100]
273
    invalid_indexes.each do |i|
274
      assert_raises(IndexError, NotImplementedError, "index=<#{i}>") do
275
        HISTORY.delete_at(i)
276
      end
277
    end
278
    
279
    invalid_indexes = [100_000_000_000_000_000_000,
280
                       -100_000_000_000_000_000_000]
281
    invalid_indexes.each do |i|
282
      assert_raises(RangeError, NotImplementedError, "index=<#{i}>") do
283
        HISTORY.delete_at(i)
284
      end
285
    end
286
  end
287

  
288
  private
289

  
290
  def push_history(num)
291
    lines = []
292
    num.times do |i|
293
      s = "a"
294
      i.times do
295
        s = s.succ
296
      end
297
      lines.push("#{i + 1}:#{s}")
298
    end
299
    HISTORY.push(*lines)
300
    return lines
301
  end
302
end if defined?(::Readline) && defined?(::Readline::HISTORY) &&
303
  (
304
   begin
305
     Readline::HISTORY.clear
306
   rescue NotImplementedError
307
     false
308
   end
309
   )