YAMAGUCHI::weblog

土足で窓から失礼いたします。今日からあなたの息子になります。 当年とって92歳、下町の発明王、エジソンです。

file:pwirte/3 と etsを使ってみた

一昨日書いたコードに追記して、結果をファイルに記録してみるようにしてみた。複数のプロセスで1つのファイルに書き込むのもMutexとか使わずに簡単に書けたのでびっくりした。

% 
% grep.erl -- find patterns from multiple files
% 
% usage: 
%      (erl)>grep:main({filename, pattern, [file1, file2, file3, ..])
%
% version 0.2
%
% todo:
%     1. exception processing for invalid arguments.
%     2. launch grep() as a server
%     3. show line number if option is handed to arguments
%


-module(grep).
-export([main/1]).
-compile(export_all).


main({LogFile, Pattern, Files}) ->
    ets:new(tfile, [public, named_table, bag]),
    ets:insert(tfile, {"logfile", LogFile}),

    lists:map(fun(F) -> filep(Pattern,F) end, Files).


filep(Pattern, File) ->
    case file:open(File, [read]) of
        {ok, Fd} ->
            ets:insert(tfile, {Fd, File}),
            spawn(grep, loop, [Pattern, Fd]);
        {error, Reason} ->
            io:format("~s : ~s", [error, Reason])
    end.
	

loop(Pattern, Fd) ->
    case file:read_line(Fd) of
        {ok, Line} -> 
            case re:run(Line, Pattern) of
                {match, _} ->
                    [Head | _] = ets:lookup(tfile, "logfile"),
                    {_, LogF} = Head,
                    {ok, Logd} = file:open(LogF, [append]),

                    [Filet | _] = ets:lookup(tfile, Fd),
                    {_, File} = Filet,
                    Log =  File ++ " -> " ++ Line,

                    {ok, TailPosition} = file:position(Logd, eof),
                    file:pwrite(Logd, TailPosition, Log),
                    file:close(Logd);
                nomatch ->
                    ok
            end,
            loop(Pattern, Fd);
        eof ->
            file:close(Fd);
        _ ->
            ok
    end.

若干気になるのはets:lookup/2では{key, value}のObjectを返してしまうので、いちいちパターンマッチでvalueを取り出してるけど、これはすごくスマートじゃないし、絶対f(key) -> valueってなるような関数があるはずだよなあ。
ご指導願います。