Sunday, November 22, 2015

Luaのdofileで使うファイルシステムを置き換える

Luaはdofile等でスクリプトを読み込む時にfopenを使います。しかし、AndroidのAPKのassetsフォルダはfopenでアクセスできません。独自のファイルシステムを構築したい場合もあります。

そういう時は、以下のようにして、標準のdofileを上書きしてファイルシステムを置き換えます。



LoadFile関数はファイル名を受け取ってmallocで確保したメモリブロックにファイルの内容を格納して返すようにしました。例えばAndroidの場合はassetsフォルダからファイルを持ってくるようにします。このエントリを参考にしてください。

luaL_loadbuffer関数にスクリプトの内容とファイル名を渡します。ファイル名は万一スクリプト内でエラーが発生した場合にLuaがどのファイルの何行目なのかを知らせてくれる為に重要です。

lua_pcallは、読み込んだスクリプトを一度「実行」します。Cのような言語と違い、Luaは関数や変数の定義も「実行」することで行われますので、これをしないとスクリプトを読み込まなかったのと同じことになります。

luaL_loadbuffer又はlua_pcallでエラーが発生した場合、Luaスタックの最上位にエラーメッセージが入ります。ここでは、適当にメッセージを加工してluaL_errorに渡します。これによって、dofileの呼び出し元のスクリプト側のエラーとして処理されます。

最後のreturn lua_gettop(L) - 1;lua_pcallがスタック何かを積んだ場合、その個数を呼び出し元に返します。-1するのはdofileが受け取ったファイル名がスタックを一つ使っているのでそれを除外するためです。説明より実例のほうがわかりやすいと思うので、以下に書いてみました。例えば、以下のような事ができるようになります。



呼びだされたcallee.luaの最後の行にreturn文があり、その戻り値をcaller.luaで受け取っています。こういった使い方が必要ない場合は、return lua_gettop(L) - 1;はreturn 0;に置き換えても不都合はありません。ただし、caller.luaはdofileから戻り値を受け取れなくなります。