CGIを書くときとか、実行ファイルが置いてあるパスが欲しい事がある。
設定ファイルやデータの読み書きをするために。
一応System.EnvironmentのgetProgNameで実行ファイルの名前は取れるんだけど、これにはパス名が付いてない。
getArgsにも入ってないし。
System.DirectoryにgetCurrentDirectoryがあるけど、カレントディレクトリじゃないんだよなぁ。特にCGI実行の時は。
どうすんだ。
と思ってググっていたら、Haskell-cafeでも同じ話題で延々と盛り上がってた。
http://www.haskell.org/pipermail/haskell-cafe/2011-December/097217.html
結論としては、そういう機能は無い。無いものは無いので、パス付きのファイル名を取得するためだけに作られたこのsystem-argv0パッケージを入れろってことらしいです。
http://hackage.haskell.org/package/system-argv0-0.1
argv0.hs
import System.Argv0 main :: IO () main = getArgv0 >>= print
これを実行する。
% ghc argv0.hs % ./argv0 FilePath "./argv0" % ../test/argv0 FilePath "../test/argv0"
おめでとうございます。
これくらいSystem.Environmentに入れてくださいよーって感じですよね。
ただ、ソースは見なかったことにしたい感じでした。Environmentだし仕方ないか。
おまけ
逆にWebサーバ側をいじる手もある。いや、無いけど。
CGI実行時にWebサーバのカレントディレクトリを変更するという手が無くはない。
単にMightyのソースいじってみましたという話です。
mighttpd2/FileCGIApp.hs
15 fileCgiApp :: ClassicAppSpec -> FileAppSpec -> CgiAppSpec -> RevProxyAppSpec -> RouteDB -> Application (略) 30 Found (RouteCGI src dst) -> 31 cgiApp cspec cgispec (CgiRoute src dst) req
このへんを
12 import System.Directory (略) 16 fileCgiApp :: ClassicAppSpec -> FileAppSpec -> CgiAppSpec -> RevProxyAppSpec -> RouteDB -> Application (略) 31 Found (RouteCGI src dst) -> do 32 liftIO $ setCurrentDirectory $ pathString dst 33 cgiApp cspec cgispec (CgiRoute src dst) req
こんな感じに書き換えると、CGI実行時のカレントディレクトリがrouteで指定したディレクトリになります。これはこれで自然な動きな気がしますけどね。
実はパス付きのプログラム名を取得するよりこっちの方が簡単だったのでしばらくこれで動かしてました。