ONC+ 開発ガイド

配列

XDR ライブラリパッケージでは、任意の要素で構成される配列を処理するプリミティブが提供されています。xdr_bytes() ルーチンは一般の配列のサブセットを処理します。すなわち、xdr_bytes() ルーチンでは、配列要素のサイズは 1 に決まっており、各要素の外部記述も組み込まれています。一般の配列に対するプリミティブ xdr_array() の引数は、xdr_bytes() の引数より 2 つ多く、配列要素のサイズと、各要素を変換する XDR ルーチンとが渡されます。渡された XDR ルーチンは、配列の各要素の符号化または復号化のときに呼び出されます。

bool_t
xdr_array(xdrs, ap, lp, maxlength, elementsize, xdr_element)
   XDR *xdrs;
   char **ap;
   u_int *lp;
   u_int maxlength;
   u_int elementsize;
   bool_t (*xdr_element)();

引数 ap は、配列へのポインタのアドレスです。配列をデシリアライズするときに *apNULL の場合は、適切なサイズの配列が割り当てられ、*ap はその配列を指すように設定されます。配列をシリアライズするときは、配列の要素数を *lp から取り出します。 配列をデシリアライズするときは、*lp には配列の長さが設定されます。引数 maxlength は、配列に入れることができる最大要素数です。 elementsiz は、配列の各要素のサイズ (バイト数) です。C の sizeof() 関数を使用してこの値を調べることができます。xdr_element() ルーチンは、配列の各要素のシリアライズ、デシリアライズ、解放を行うときに呼び出されます。

他の合成データ型を定義する前に、3 つの例を示します。

配列変換サンプルプログラム 1

ネットワーク上のマシンのユーザーは次に基づいて特定できます。

この情報を持つ構造体とそれに関連付けられた XDR ルーチンは次のコーディング例に示す方法でコード化できます。


例 A–7 配列変換サンプルプログラム 1

struct netuser {
 	char  *nu_machinename;
 	int   nu_uid;
 	u_int nu_glen;
 	int   *nu_gids;
 };
#define NLEN 255       /* マシン名は 255 文字以下 */
#define NGRPS 20       /* ユーザーが所属するグループ数は 20 以下 */
 
bool_t
xdr_netuser(xdrs, nup)
 	XDR *xdrs;
 	struct netuser *nup;
{
 	return(xdr_string(xdrs, &nup->nu_machinename, NLEN) &&
 		    xdr_int(xdrs, &nup->nu_uid) &&
 		    xdr_array(xdrs, &nup->nu_gids, &nup->nu_glen, NGRPS,
		               sizeof (int), xdr_int));
}

配列変換サンプルプログラム 2

ネットワークユーザーのグループを netuser 構造体の配列で表すことができます。次のコーディング例では宣言およびそれに関連付けられた XDR ルーチンを示します。


例 A–8 配列変換サンプルプログラム 2

struct party {

 	u_int p_len;
 	struct netuser *p_nusers;
};
#define PLEN 500 /* グループに所属するユーザー数の上限 */
bool_t
xdr_party(xdrs, pp)
 	XDR *xdrs;
 	struct party *pp;
{
 	return(xdr_array(xdrs, &pp->p_nusers, &pp->p_len, PLEN,
 	 sizeof (struct netuser), xdr_netuser));
}

配列変換サンプルプログラム 3

main に対するよく知られた引数 argcargv を組み合わせて構造体を作成します。 これらの構造体の配列でコマンドヒストリを作成できます。構造体の宣言とその XDR ルーチンは次の例のようになります。


例 A–9 配列変換サンプルプログラム 3

struct cmd {
 	u_int c_argc;
 	char **c_argv;
};
#define ALEN 1000           /* argc は 1000 以下 */
 #define NARGC 100          /* 各コマンドの args は 100 以下 */

struct history {
 	u_int h_len;
 	struct cmd *h_cmds;
};
#define NCMDS 75            /* ヒストリは 75 コマンドまで */

bool_t
xdr_wrapstring(xdrs, sp)

 	XDR *xdrs;
 	char **sp;
{
 	return(xdr_string(xdrs, sp, ALEN));

}

bool_t
xdr_cmd(xdrs, cp)

 	XDR *xdrs;
 	struct cmd *cp;
{
 	return(xdr_array(xdrs, &cp->c_argv, &cp->c_argc, NARGC,
 	        sizeof (char *), xdr_wrapstring));
}
bool_t
xdr_history(xdrs, hp)

 	XDR *xdrs;
 	struct history *hp;
{
 	return(xdr_array(xdrs, &hp->h_cmds, &hp->h_len, NCMDS,
 	        sizeof (struct cmd), xdr_cmd));
}

このプログラムの複雑な点は、xdr_string() を呼び出すためのルーチン xdr_wrapstring() が必要な点です。xdr_array() が配列要素記述ルーチンを呼び出すときは引数が 2 つしか渡されないため、xdr_string() の第 3 パラメータを提供するルーチン xdr_wrapstring() が必要になります。xdr_wrapstring()xdr_string() へ第 3 パラメータを提供します。

これまでの説明で XDR ライブラリの再帰的性質が明らかになりました。合成データ型についてさらに説明します。