***その1
SWIGのタイプマップについて調べているのですが、Tclのコマンドを作るときに、引数の省略やリストの受け渡しといった、気のきいたインターフェースを作るにはなかなかややこしくて、結局タイプマップファイルと生成されたラッパーコードを比較しながらうまいやり方を見つけていくしかないのかなあと思います。で、色々と考察したいと思います。まずは、引数にリストを渡す場合を考えたいと思います。
%sum { 1 2 3 4 5}
1 2 3 4 5 = 15
と、このようにリストの値を合計するようなコマンドを作りたいと思います。Cのコード test.c はこんな風に普通に書きます。
void sum(int list[], int len) {
int i;
int sum=0;
for (i=0; i<len; i++){
sum += list[i];
printf("%d ", list[i]);
}
printf("= %d\n", sum);
}
で、インターフェースファイル test.i はこんな感じになります
%module test
%typemap(in) (int list[], int len) {
int i;
Tcl_Obj *tclobj=NULL;
/*リストオブジェクトの長さの取得*/
if(Tcl_ListObjLength(interp, $input, &$2)==TCL_ERROR){
return TCL_ERROR;
}
/*リストオブジェクトを新しいint配列に変換*/
$1 = (int*) malloc($2 * sizeof(int));
for(i=0; i<$2; i++) {
Tcl_ListObjIndex(interp, $input, i, &tclobj);
Tcl_GetIntFromObj(interp, tclobj, $1+i);
}
}
%typemap(freearg) (int list[], int len) {
if ($1) free($1);
}
extern void sum(int list[], int len);
%typemap(in) (int list[], int len)でCのsum関数に対応した引数を作ってます。$1がint list[] 、$2がint lenに対応しています。実際に生成されるラッパーコードでは、$1はint *arg1、$2は int arg2に置き換えられてtypemap(in)のコードが埋め込まれ、次に本体のコードがsum(arg1, arg2)という風に呼び出されて、最後にtypemap(freearg)のコードで確保したメモリを解放するというわけです。 で、こいつからswig -tcl test.iとかやると、test_wrap.cとか出来るので、適当にコンパイルしてやればOKです。
%load test
%sum { 1 2 3 4 5}
1 2 3 4 5 = 15
% sum 1
1 = 1
まあ、こんなもんでしょうかね・・・。それじゃあ・・・
% sum 1 2
Wrong # args.:sum list ?len? argument 2
% sum {1 2 a}
1 2 1735289204 = 1735289207
expected integer but got "a"
% sum a
0 = 0
expected integer but got "a"
引数は1つしか取らないのでエラーになるのはいいんですが、?len?というのはlenという引数が省略できますよというなので、?list?の部分は無い方がいいんですが・・・。どうやって引数のエラーメッセージを書き換えるんだろう・・・。あと、文字列も数値になっちゃうのも、まあ現状の変換部分で書いてないので構わないんですが、expected integer but got "a"のエラーメッセージはどこから出てきてるのか追っかけないといけない(のがめんどくさい)ような。 expected integer but got "a"のようなエラーはたぶんResultがセットされてないからだと思うんですが、sumがvoidだからって何もSetResultしてくれないというのはちょっと・・・。catch {sum {a}} msg のようなエラー処理ができないもんですかね・・・。つーかこれもタイプマップで書かないとダメなのか。ということは、リストオブジェクトをまず文字列の配列にして数値変換かましていけばいいのかな。
***その2
----
[[CategoryTclTk]][[CategorySWIG]]
HTML convert time: 0.002 sec.