Blog

Term::EditLine の history 関連API がこわれてたのでパッチをかいてみた

https://rt.cpan.org/Ticket/Display.html?id=83107&results=854b66a3a5371408eb225e1b6d245eff

こんなかんじです。昔はうごいていて今はうごいていないのか、どうかわかりませんが、たぶん普通に最初からうごいてない気がします。

diff --git a/EditLine.xs b/EditLine.xs
index f541083..5abbc4a 100644
--- a/EditLine.xs
+++ b/EditLine.xs
@@ -352,7 +352,7 @@ CODE:
   free(he);
 }
 
-void
+int
 el_history_set_size(he,size)
          HistEdit *he
          int size
@@ -360,10 +360,12 @@ PREINIT:
 HistEvent ev;
 CODE:
 {
-  history(he->hist,&ev,H_SETSIZE,size);
+  RETVAL = history(he->hist,&ev,H_SETSIZE,size);
 }
+OUTPUT:
+  RETVAL
 
-void
+int
 el_history_enter(he,str)
      HistEdit *he
      char *str
@@ -371,10 +373,12 @@ PREINIT:
   HistEvent ev;
 CODE:
 {
-  history(he->hist,&ev,H_ENTER,str);
+  RETVAL = history(he->hist,&ev,H_ENTER,str);
 }
+OUTPUT:
+  RETVAL
 
-void
+int
 el_history_append (he,str)
      HistEdit *he
      char *str
@@ -382,10 +386,12 @@ PREINIT:
   HistEvent ev;
 CODE:
 {
-  history(he->hist,&ev,H_APPEND,str);
+  RETVAL = history(he->hist,&ev,H_APPEND,str);
 }
+OUTPUT:
+  RETVAL
 
-void
+int
 el_history_add (he,str)
      HistEdit *he
      char *str
@@ -393,122 +399,160 @@ PREINIT:
   HistEvent ev;
 CODE:
 {
-  history(he->hist,&ev,H_ADD,str);
+  RETVAL = history(he->hist,&ev,H_ADD,str);
 }
+OUTPUT:
+  RETVAL
 
-int
+void
 el_history_get_size (he)
      HistEdit *he
 PREINIT:
   HistEvent ev;
-CODE:
+PPCODE:
 {
-  history(he->hist,&ev,H_GETSIZE);
-  RETVAL = ev.num;
+  dTARG;
+  int ret = history(he->hist,&ev,H_GETSIZE);
+  if (GIMME_V == G_ARRAY) {
+    mXPUSHi(ret);
+  }
+  mXPUSHi(ev.num);
 }
 
-void
+int
 el_history_clear (he)
      HistEdit *he
 PREINIT:
   HistEvent ev;
 CODE:
 {
-  history(he->hist,&ev,H_CLEAR);
+  RETVAL = history(he->hist,&ev,H_CLEAR);
 }
+OUTPUT:
+  RETVAL
 
-const char *
+void
 el_history_get_first(he)
      HistEdit *he
 PREINIT:
   HistEvent ev;
-CODE:
+PPCODE:
 {
-  history(he->hist,&ev,H_FIRST);
-  RETVAL = ev.str;
+  dTARG;
+  int ret = history(he->hist,&ev,H_FIRST);
+  if (GIMME_V == G_ARRAY) {
+    mXPUSHi(ret);
+  }
+  mXPUSHp(ev.str, strlen(ev.str));
 }
 
-const char *
+void
 el_history_get_last(he)
      HistEdit *he
 PREINIT:
   HistEvent ev;
-CODE:
+PPCODE:
 {
-  history(he->hist,&ev,H_LAST);
-  RETVAL = ev.str;
+  dTARG;
+  int ret = history(he->hist,&ev,H_LAST);
+  if (GIMME_V == G_ARRAY) {
+    mXPUSHi(ret);
+  }
+  mXPUSHp(ev.str, strlen(ev.str));
 }
 
-const char *
+void
 el_history_get_prev(he)
      HistEdit *he
 PREINIT:
   HistEvent ev;
-CODE:
+PPCODE:
 {
-  history(he->hist,&ev,H_PREV);
-  RETVAL = ev.str;
+  dTARG;
+  int ret = history(he->hist,&ev,H_PREV);
+  if (GIMME_V == G_ARRAY) {
+    mXPUSHi(ret);
+  }
+  mXPUSHp(ev.str, strlen(ev.str));
 }
 
 
-const char *
+void
 el_history_get_next(he)
      HistEdit *he
 PREINIT:
   HistEvent ev;
-CODE:
+PPCODE:
 {
-  history(he->hist,&ev,H_NEXT);
-  RETVAL = ev.str;
+  dTARG;
+  int ret = history(he->hist,&ev,H_NEXT);
+  if (GIMME_V == G_ARRAY) {
+    mXPUSHi(ret);
+  }
+  mXPUSHp(ev.str, strlen(ev.str));
 }
 
 
-const char *
+void
 el_history_get_curr(he)
      HistEdit *he
 PREINIT:
   HistEvent ev;
-CODE:
+PPCODE:
 {
-  history(he->hist,&ev,H_CURR);
-  RETVAL = ev.str;
+  dTARG;
+  int ret = history(he->hist,&ev,H_CURR);
+  if (GIMME_V == G_ARRAY) {
+    mXPUSHi(ret);
+  }
+  mXPUSHp(ev.str, strlen(ev.str));
 }
 
-void
+int
 el_history_set(he)
      HistEdit *he
 PREINIT:
   HistEvent ev;
 CODE:
 {
-  history(he->hist,&ev,H_SET);
+  RETVAL = history(he->hist,&ev,H_SET);
 }
+OUTPUT:
+  RETVAL
 
-const char *
+void
 el_history_get_prev_str(he,str)
      HistEdit *he
      char *str
 PREINIT:
   HistEvent ev;
-CODE:
+PPCODE:
 {
-  history(he->hist,&ev,H_PREV_STR,str);
-  RETVAL = ev.str;
+  dTARG;
+  int ret = history(he->hist,&ev,H_PREV_STR,str);
+  if (GIMME_V == G_ARRAY) {
+    mXPUSHi(ret);
+  }
+  mXPUSHp(ev.str, strlen(ev.str));
 }
 
-const char *
+void
 el_history_get_next_str(he,str)
      HistEdit *he
      char *str
 PREINIT:
   HistEvent ev;
-CODE:
+PPCODE:
 {
-  history(he->hist,&ev,H_NEXT_STR,str);
-  RETVAL = ev.str;
+  dTARG;
+  int ret = history(he->hist,&ev,H_NEXT_STR,str);
+  if (GIMME_V == G_ARRAY) {
+    mXPUSHi(ret);
+  }
+  mXPUSHp(ev.str, strlen(ev.str));
 }
 
-void
+int
 el_history_load(he,str)
      HistEdit *he
      char *str
@@ -516,10 +560,12 @@ PREINIT:
   HistEvent ev;
 CODE:
 {
-  history(he->hist,&ev,H_LOAD,str);
+  RETVAL = history(he->hist,&ev,H_LOAD,str);
 }
+OUTPUT:
+  RETVAL
 
-void
+int
 el_history_save(he,str)
      HistEdit *he
      char *str
@@ -527,8 +573,10 @@ PREINIT:
   HistEvent ev;
 CODE:
 {
-  history(he->hist,&ev,H_SAVE,str);
+  RETVAL = history(he->hist,&ev,H_SAVE,str);
 }
+OUTPUT:
+  RETVAL
 
 int
 el_insertstr(he, str)
diff --git a/Makefile.PL b/Makefile.PL
index 3d6a5d8..85fe985 100644
--- a/Makefile.PL
+++ b/Makefile.PL
@@ -7,7 +7,9 @@ use ExtUtils::MakeMaker;
 WriteMakefile(
     'NAME'		=> 'Term::EditLine',
     'VERSION_FROM'	=> 'EditLine.pm', # finds $VERSION
-    'PREREQ_PM'		=> {}, # e.g., Module::Name => 1.1
+    'PREREQ_PM'		=> {
+         'Test::More' => 0.96,
+	},
     ($] >= 5.005 ?    ## Add these new keywords supported since 5.005
       (ABSTRACT_FROM => 'EditLine.pod', # retrieve abstract from module
        AUTHOR     => 'Ulrich Burgbacher <[email protected]>') : ()),
diff --git a/t/2.t b/t/2.t
new file mode 100644
index 0000000..f2822d9
--- /dev/null
+++ b/t/2.t
@@ -0,0 +1,167 @@
+use strict;
+use warnings;
+use utf8;
+use Test::More;
+use Term::EditLine;
+
+my $el;
+
+sub context;
+
+$ENV{LANG} = 'C';
+
+subtest 'history_get_size' => sub {
+    context 'scalar' => sub {
+        is(0+$el->history_get_size(), 0);
+    };
+    context 'list' => sub {
+        my ($a, $b) = $el->history_get_size();
+        is($a, 0);
+        is($b, 0);
+    };
+    context 'scalar after enter' => sub {
+        is(0+$el->history_get_size(), 0);
+        $el->history_enter('hoge');
+        is(0+$el->history_get_size(), 1);
+    };
+};
+
+subtest 'history_clear' => sub {
+    context 'input and clear' => sub {
+        is(0+$el->history_get_size(), 0);
+        $el->history_enter('hoge');
+        is(0+$el->history_get_size(), 1);
+        $el->history_clear();
+        is(0+$el->history_get_size(), 0);
+    };
+};
+
+subtest 'history_get_first' => sub {
+    context 'scalar in empty' => sub {
+        is(scalar($el->history_get_first()), 'first event not found');
+    };
+    context 'list in empty' => sub {
+        my ($a, $b) = $el->history_get_first();
+        is($a, -1);
+        is($b, 'first event not found');
+    };
+    context 'scalar after enter' => sub {
+        $el->history_enter('hoge');
+        $el->history_enter('fuga');
+        is(scalar($el->history_get_first()), 'fuga');
+    };
+};
+
+subtest 'history_get_last' => sub {
+    context 'scalar in empty' => sub {
+        is(scalar($el->history_get_last()), 'last event not found');
+    };
+    context 'list in empty' => sub {
+        my ($a, $b) = $el->history_get_last();
+        is($a, -1);
+        is($b, 'last event not found');
+    };
+    context 'scalar after enter' => sub {
+        $el->history_enter('hoge');
+        $el->history_enter('fuga');
+        is(scalar($el->history_get_last()), 'hoge');
+    };
+};
+
+subtest 'history_get_prev' => sub {
+    context 'scalar in empty' => sub {
+        is(scalar($el->history_get_prev()), 'empty list');
+    };
+    context 'list in empty' => sub {
+        my ($a, $b) = $el->history_get_prev();
+        is($a, -1);
+        is($b, 'empty list');
+    };
+    context 'scalar after enter' => sub {
+        $el->history_enter('hoge');
+        $el->history_enter('fuga');
+        is(scalar($el->history_get_prev()), 'no previous event');
+        is(scalar($el->history_get_first()), 'fuga');
+        is(scalar($el->history_get_prev()), 'no previous event');
+    };
+};
+
+subtest 'history_get_next' => sub {
+    context 'scalar in empty' => sub {
+        is(scalar($el->history_get_next()), 'empty list');
+    };
+    context 'list in empty' => sub {
+        my ($a, $b) = $el->history_get_next();
+        is($a, -1);
+        is($b, 'empty list');
+    };
+    context 'scalar after enter' => sub {
+        $el->history_enter('hoge');
+        $el->history_enter('fuga');
+        is(scalar($el->history_get_next()), 'hoge');
+        is(scalar($el->history_get_next()), 'no next event');
+    };
+};
+
+subtest 'history_get_curr' => sub {
+    context 'scalar in empty' => sub {
+        is(scalar($el->history_get_curr()), 'empty list');
+    };
+    context 'list in empty' => sub {
+        my ($a, $b) = $el->history_get_curr();
+        is($a, -1);
+        is($b, 'empty list');
+    };
+    context 'scalar after enter' => sub {
+        $el->history_enter('hoge');
+        $el->history_enter('fuga');
+        is(scalar($el->history_get_curr()), 'fuga');
+        is(scalar($el->history_get_curr()), 'fuga');
+    };
+};
+
+subtest 'history_set' => sub {
+    context 'scalar in empty' => sub {
+        is(scalar($el->history_set()), -1);
+    };
+};
+
+subtest 'history_get_prev_str' => sub {
+    context 'scalar after enter' => sub {
+        $el->history_enter('hoge');
+        $el->history_enter('fuga');
+        is(scalar($el->history_get_prev_str('h')), 'hoge');
+    };
+};
+
+subtest 'history_get_next_str' => sub {
+    context 'scalar after enter' => sub {
+        $el->history_enter('hoge');
+        $el->history_enter('fuga');
+        is(scalar($el->history_get_next_str('f')), 'fuga');
+    };
+};
+
+subtest 'history_save, history_load' => sub {
+    context 'save and load' => sub {
+        unlink 't/history.dat' if -f 't/history.dat';
+        $el->history_enter('hoge');
+        $el->history_enter('fuga');
+        is($el->history_save('t/history.dat'), 2);
+
+        my $el2 = Term::EditLine->new($0);
+        is($el2->history_get_size(), 0);
+        $el2->history_load('t/history.dat');
+        is($el2->history_get_size(), 2);
+
+        unlink 't/history.dat' if -f 't/history.dat';
+    };
+};
+
+done_testing;
+
+sub context {
+    my ($name, $code) = @_;
+    $el = Term::EditLine->new($0);
+    goto &Test::More::subtest;
+}

このパッチがはいれば、Term::ReadLine::EditLine にヒストリー関連の機能がつきます。