環境リソース管理 (overview)

# 環境リソース (overview)

## 説明

ENVライブラリでは、プログラムからリソースとして定義した値を容易に取得する手段を提供します。リソースとはリソース名の定義された、様々なパラメータや設定値です。プログラムからはリソース名の指定でリソース値を取得します。

プログラムの開発途中で動作のためのパラメータを様々に変えて実験を行なうような場合や、複数のプログラムで共通の設定値を用いるような場合にこの環境リソースライブラリを用いると非常に便利です。

### リソース定義

この ENV ライブラリでは、リソース名の問い合わせに対し、リソース値を返します。リソース名は、クラス名、"." (ピリオド) 、メンバ名　で構成されます。

> (例)
> `myServer.Hostname`というリソースの場合、
> `myServer` がクラス名で、 `Hostname` がメンバ名です。

こうしたりソースに対し、u8, s8, u16, s16, u32, s32, u64, s64, BOOL, string, binary のいずれかの値を持たせることが出来ます。string は文字列データで、binary はバイナリデータです。

リソースは内部では１つの `ENVResource` 構造体で管理されます。( リソース値が 64ビット値の場合は2つ使用します)

> `struct ENVResource
> {
> char*　 name;
> u16 　　len;
> u16 　　type;
> void*　 ptr;
> };`

name はリソース名へのポインタです。len はりソースの長さです。type はりソースを宣言したときの型情報です。ptr は、string と binary の場合は、文字列やデータが実際に格納されている場所へのポインタです。u8, s8, u16, s16, u32, s32, BOOLの場合はその値が代入されます。u64 と s64 の場合は、連続する2つのリソースデータを用います。

### リソースデータの記述

リソースデータは `ENVResource` 構造体の配列で定義します。前述の `ENVResource` 構造体の、len, type, ptr メンバを一度に定義する以下のマクロが用意されていて、これを利用するとリソースの記述も簡単です。

`ENV_U8()` | `u8 値に対するマクロ`
`ENV_S8()` | `s8 値に対するマクロ`
`ENV_U16()` | `u16 値に対するマクロ`
`ENV_S16()` | `s16 値に対するマクロ`
`ENV_U32()` | `u32 値に対するマクロ`
`ENV_S32()` | `s32 値に対するマクロ`
`ENV_U64()` | `u64 値に対するマクロ`
`ENV_S64()` | `s64 値に対するマクロ`
`ENV_BOOL()` | `BOOL値に対するマクロ`
`ENV_STRING()` | `文字列に対するマクロ`
`ENV_BINARY()` | `バイナリデータに対するマクロ`

これらを用いて、以下のように リソース名とリソースマクロの組でリソースを定義します。

> `ENVResource myResource[] = {
> "myClass.str1",　　　　ENV_STRING( "mario" ),
> "myClass.bin1",　　　　ENV_BINARY( "\x12\x34\x56\x78" ),
> "myClass2.data1",　　 ENV_S32( -500 ),
> "myClass2.data2",　　 ENV_U16( 0x8000 ),
> ENV_RESOURCE_END
> };`

`データの最後には ENV_RESOURCE_END を記述してください。`

上で定義したリソース配列は、内部ではこのように管理されます。

> `
> `

### リソース配列のリスト

リソースの検索はリソース配列から行なわれますが、ENVライブラリではシステムに複数のリソース配列を登録できるようになっています。リソース配列はシステム内でリストとして連結され、検索時はこのリストを元に、登録されているすべての配列を対象に行なわれます。検索はリストのより前、そして配列のより前から検索され、同じリソースがあった場合は先に見つかったほうが採用されます。

`ENV_AppendResourceSet()` は新たなリソース配列をリストの最後尾に追加します。
`ENV_PrependResourceSet()` は新たなリソース配列をリストの先頭に追加します。
`ENV_InsertResourceSet()` は新たなリソース配列を任意の位置に追加します。

`ENV_SetResourceSet()`, `ENV_SetResourceSetArray()` はこれまで登録されていたリストを破棄し、指定のものを登録します。

登録できるリソース配列の数には制限があります。ENV_RESOURCE_SET_MAX 個です。(8 に定義されています)

### リソース配列の宣言

`ENV_Init()` ではリソース配列を以下のように、 `ENVResource* resourceArray[]` 配列で指定しています。

> `SDK_WEAK_SYMBOL ENVResource *resourceArray[] = { NULL };
> void ENV_Init(void)
> {
> ：
> ENV_SetResourceSetArray( resourceArray );
> }`

`resourceArray[]` はリソース配列を持つ配列です。システムでは WEAK シンボルとして NULL メンバの配列になっていますので、アプリ側が自分でこの配列を定義すればそちらが有効になります。`resourceArray[]` はリソース配列の配列なので、必要なリソース配列を複数まとめることで一度に指定することができます。

### リソース値の取得

リソース名からリソース値を取得する関数は、リソースの定義によって以下のように使い分けてください。

`ENV_GetU8()` | `ENV_U8() で定義した u8 値`
`ENV_GetS8()` | `ENV_S8() で定義した s8 値`
`ENV_GetU16()` | `ENV_U16() で定義した u16 値`
`ENV_GetS16()` | `ENV_S16() で定義した s16 値`
`ENV_GetU32()` | `ENV_U32() で定義した u32 値`
`ENV_GetS32()` | `ENV_S32() で定義した s32 値`
`ENV_GetU64()` | `ENV_U64() で定義した u64 値`
`ENV_GetS64()` | `ENV_S64() で定義した s64 値`
`ENV_GetBOOL()` | `ENV_BOOL() で定義した BOOL値`
`ENV_GetString()` | `ENV_STRING() で定義した 文字列`
`ENV_GetBinary()` | `ENV_BINARY() で定義した バイナリデータ`

取得値は引数に指定するポインタの先に格納されます。関数の返り値は取得に成功したかどうかを表します。

文字列とバイナリ取得の関数は、その大きさを併せて取得するために、`ENV_GetStringAndLength()`, `ENV_GetBinaryAndSize()` が用意されています。

### クラス名の省略

予め、クラス名を ENVライブラリに与えることで、リソース名を必要とする関数でクラス名の部分を省略してメンバ名のみで指定することが出来ます。メンバ名のみを指定するときには、"." (ピリオド) を最初に付けてください。

クラス名の宣言は、`ENV_SetClass()` で行ないます。

> (例)
> `u32 d1, d2, d3;
> (void)ENV_GetU32( "myClass.myData1", &d1 );
> (void)ENV_GetU32( "myClass.myData2", &d2 );
> (void)ENV_GetU32( "myClass.myData3", &d3 );
> `
> とすべてにクラス名を記述するところを、
> `u32 d1, d2, d3;
> ENV_SetClass( "myClass" );
> (void)ENV_GetU32( ".myData1", &d1 );
> (void)ENV_GetU32( ".myData2", &d2 );
> (void)ENV_GetU32( ".myData3", &d3 );
> `
> というようにメンバ名のみで記述できます。

現在の設定値を取得する関数は `ENV_GetClass()` です。

### ENVライブラリ使用例

以下は ENV ライブラリを使用した例です。

> `ENVResource myResource1[] = {
> "server1.hostName",　　ENV_STRING( "myserver" ),
> "server1.IP",　　ENV_BINARY( "\xc0\xA8\x00\x01" ),
> "server1.port",　　ENV_U16( 5000 ),
> ENV_RESOUCE_END
> };
> ENVResource myResource2[] = {
> "server2.hostName",　　ENV_STRING( "ftpserver" ),
> "server2.IP",　　ENV_BINARY( "\xc0\xA8\x00\x02" ),
> "server2.port",　　ENV_U16( 21 ),
> ENV_RESOUCE_END
> };
> ENVResource* resourceArray[]={ myResource1, myResource2, NULL };
> main()
> {
> char* hostname;
> u8* ipAddress;
> int ipSize;
> u16 portNum;
> ：
> //---- ENV システムの初期化
> ENV_Init();
> //---- 省略時クラス名の指定
> ENV_SetClass( "server1" );
> //---- リソースの取得
> if ( ! ENV_GetString( ".hostName", &hostname ) )
> {
> OS_Printf( "error: hostname is not defined.\n" );
> };
> if ( ! ENV_GetBinaryAndSize( ".IP", &ipAddress, &ipSize) )
> {
> OS_Printf( "error: ipAddress is not defined.\n" );
> };
> if ( ! ENV_GetU16( ".port", &portNum ) )
> {
> OS_Printf( "error: portNum is not defined.\n" );
> };
> ：
> }
> `

### 特定の条件でリソースを検索

特定のクラス名やメンバ名などで検索してリソースを検索するために ENVResourceIter 構造体が定義されています。これを検索のイテレータとして用います。イテレータを操作してリソースを取得する関数として、`ENV_InitIter()` と、`ENV_SearchByClass()` 、 `ENV_SearchByMember()`、`ENV_SearchByType()`、`ENV_SearchByPartialName()` があります。

以下は特定のクラス "className" を持つリソースを取得しています。

> `ENVResourceiter　 iter;``
> ENVResource* 　　　p;
> ENV_InitIter( &iter );
> while( (p = ENV_SearchByClass( &iter, "className" ) ) )
> {
> OS_Printf( "resource = %s\n", p->name );
> }`

特定のメンバ名 "memberName" を持つリソースを検索するには、以下のように記述します。メンバ名は、"."(ピリオド) を含まない文字列となります。クラス、メンバの区切りのピリオド以外にピリオドがある場合、そこまでをメンバ名として比較します。

> `ENVResourceIter　 iter;``
> ENVResource* 　　　p;
> ENV_InitIter( &iter );
> while( (p = ENV_SearchByMember( &iter, "memberName" ) ) )
> {
> OS_Printf( "resource = %s\n", p->name );
> }`

例えば、メンバ名「member」で検索する場合、

> `"class.member"
> "class.member.001"
> "class.member.class"`

`にはマッチしますが、`

> `"class.member001"
> "class.member2.member"`

にはマッチしません。

### リソースが含まれるリソース配列

イテレータを用いてリソースを検索した直後、`ENV_GetLastResourceSetFromIter()` で取得したリソースの所属するリソース配列を取得することが可能です。

リソースを指定してその所属するリソース配列を取得するのは `ENV_GetBelongingResourceSet()` です。

## 参照

`ENV関数一覧
`

## 履歴

2005/08/29 リソース配列の複数登録に対応
2005/08/17 初版