3.6.1: C 言語プログラミングインタフェースの基礎

まず, 初めに libwam の使用方法をざっと見ておきます.

まず, ヘッダファイルです. これは, geta/wam.hをインクルードすれば必要なものはだいたい入っているはずです. GETA のヘッダファイルは$GETAROOT/includeにあるので, コンパイラにその場所を教えるのも忘れてはなりません. その方法については後で説明します.

        #include <geta/wam.h>

WAM を使うには, 最初に wam_init(3) を呼びだして (プロセスごとに)初期化を行う必要があります. wam_init(3) への引き数には$GETAROOTの絶対パスを渡すのですが, NULLを渡すと環境変数GETAROOTの値が用いられるので, 大抵の場合NULLを渡しておけば十分です.

        wam_init(NULL);

次に wam_open により取り扱いたい WAM をオープンします. wam_open(3) の第1引き数にはハンドル(ショートネームも可)を渡します. 第2引き数には 0 を渡します. wam_open(3) は指定された WAM の取り扱うための資源を確保し, その WAM に関連付けられた識別子(*9)を返します. 以後, この WAM にアクセスするためにはこの識別子を用います.

        WAM *w;
        w = wam_open("my-inbox", 0);

WAM を使い終わったら wam_close(3) により資源を開放しておきます. なお, wam_close を呼ばなくてもプロセスが終了した場合, この資源は自動的に開放されます.

        wam_close(w);

行(列)の name と ID の相互変換は, wam_name2id(3) と wam_id2name(3) により行えます. ID はsymbol_t型であることに注意して下さい. 第1引き数は WAM の識別子です. また, 行と列のどちらの表を見たいのかも WAM に指示する必要があります. 行なら WAM_ROW, 列なら WAM_COL を第2引き数に渡します. これらの関数は失敗するとそれぞれ 0 と NULL ポインタを返します.

        symbol_t id;
        char *name;
        name = "inbox/1";
        if (!(id = wam_name2id(w, WAM_ROW, name))) {        /* 行: name -> ID */
                fprintf(stderr, "この name は登録されていません: [%s]\n", name);
        }

        id = 5;
        if (!(name = wam_id2name(w, WAM_COL, id))) {        /* 列: ID -> name */
                fprintf(stderr, "この ID は登録されていません: %d\n", id);
        }

次に, 行(列)の内容についてです. libwam では, 1行(列)の情報は struct xr_vec 型の変数にパックされています. elem_num は, その行に現れる値が 0 でない要素の数, freq_sum はその行の要素の値の和です. elems には値が 0 でない要素が ID の小さい順につまっています. すなわち, elems には elem_num 個の要素がつまっていることになります. 宣言では elems の要素数が 1 になっていますが, 0 .. elem_num-1 までなら安全にアクセスできます.

        struct xr_vec {
                ival_t elem_num;        /* # of elems */
                ival_t freq_sum;        /* sum of freq */
                struct xr_elem elems[1];
        };

各要素は struct xr_elem 型です. id がその要素の ID, freq がその要素の値です. symbol_t は符号無し 32 ビット整数, ival_t は符号付き 32 ビット整数です.

        struct xr_elem {
                symbol_t id;                /* network order */
                ival_t freq;                /* network order */
        };
また, ユーザの便宜を図るために以下の typedef がされています.
        typedef struct xr_elem xr_elem;
        typedef struct xr_vec xr_vec;
この構造体を取得するには wam_get_vec(3) を用います. これもやはりWAM の識別子に続いて WAM_ROW または WAM_ROL を渡します. それに続いて行(列)のID, 構造体へのポインタのポインタ, フラグを渡します. フラグに XR_HOSTORDER を渡すと 構造体に格納されているデータが普通に扱える形式に変換されます. wam_get_vec(3) の戻り値は値が 0 でない要素の数です (すなわち, 構造体の最初のメンバ, elem_num と同じ値になります. ). wam_get_vec(3) は失敗すると -1 を返します.

例えば WAM の"猿"という name が付いた列を取得するには次の様にします. (文字コードが, freqfile で使ったものと同じになるように注意して下さい. )

        xr_vec *vec;
        int elem_num;
        if (!(id = wam_name2id(w, WAM_COL, "猿"))) {
                err(1, "失敗: 猿");
        }
        if ((elem_num = wam_get_vec(w, WAM_COL, id, &vec, XR_HOSTORDER))==-1) {
                err(1, "失敗: get_vec");
        }
        assert(elem_num == vec->elem_num); /* if XR_HOSTORDER */
次の例は, 取得したベクタの要素を順に印刷しています. elems->id には xr_vec が行ベクタなら列の ID が, そうでなくて xr_vec が列ベクタなら行の ID が入っていますから, この場合はWAM_ROW で name に変換しなければなりません.
        int i;
        for (i=0; i<elem_num; i++) {
                xr_elem *e = &vec->elems[i];
                char *name;
                name = wam_id2name(w, WAM_ROW, e->id);
                printf("id=%d, name=%s, frq=%d\n", e->id, name, e->freq);
        }
これで, 前の部分と合わせると, "猿"が現れる記事の name を全て印刷するプログラムの断片になります.

ここまでのサンプルを saru.c に保存し, コンパイル/リンクします. 先にも触れたように, コンパイラにヘッダファイルの位置を教えなければなりません. 必要なライブラリは libgetamu.a と libwam.a のふたつです. libgetamu.a は libwam.a で使用する雑関数が納められており, 必須です. これらは $GETAROOT/lib にあります. 従って, コマンドは以下の様になります. ライブラリを指定する順番も大切です(*10).

        $ cc saru.c -I$GETAROOT/include -L$GETAROOT/lib -lwam -lgetamu
これでa.outができますから実行してみます.
        $ ./a.out
        ...
どうやら, うまく動いている様です.


*9: ポインタが返るので UNIX 用語ではハンドルに近いのですが, WAM のハンドルとまぎらわしいので, ここでは識別子という用語を使いました.
*10: 附属の Makefile では GETAROOT を configure で置換しています.