Home -> HSP講座 -> HPI編 No.08-1

文字列は文字の列でなくっちゃ

いきなりなんだと思った人も多いでしょう。
これはC言語の話ですね。Cでは、文字列を char[](文字配列型) で扱います。
( C++なら CString があるので楽ですが )
……というわけで、ちょっと懐古主義になって、
strのサポートされているHSPでcharを使えるようにします!!

ん、ややこしいからイラナイ?
まぁそう言わずに (^-^;

今回のソースコード:「char」リポジトリ


変数型を登録する

以前、変数の操作には HspVarProc 構造体を使うと言いましたね。 この構造体に関数ポインタをセットしてHSPに渡せば、新たな変数型が作れます。

手順はこうです。

  1. HspVarProc構造体のための関数を作る。
  2. 構造体にポインタをセットする関数を作る。
  3. 構造体をHSP側に登録する。

サクッと行きましょう、サクッと。


HspVarProc構造体の関数

まず、宣言を書きます。
全部列挙すると、こんな感じ。

うぅ、いっぱいありますが……。
大丈夫です。後半はほぼ全部同じですし、いくつかは実装しませんから。

GetVarSize_Char
これはプラグインの内部で使う関数です。
PVal構造体が、変数データのために確保すべきバッファサイズ (byte) を返します。
返値はそのまま size メンバに格納されます。
HspVarChar_Cnv
他の型の値を、char型に変換する関数です。
HSPのchar()関数などで呼び出されます。
HspVarChar_CnvCustom
char型の値を、他の型に変換する関数です。
引数 buffer は、実質 const char* 型と同じです。
HspVarChar_GetPtr
変数の実体へのポインタを返す関数です。
いつも使っていた vp->GetPtr() のアレ。
HspVarChar_Alloc
char型変数のPValを初期化する関数です。
ptメンバに動的に配列を確保したり、データを初期化したりします。
HspVarChar_Free
char型変数のPValを破棄する関数です。
Allocで確保したメモリはここで解放します。
HspVarChar_GetSize
pdatの内容のサイズを取得します。
これは、str型のように、1つの要素のサイズが可変長の時に使用するために用意されているので、後述の basesize メンバと同じ値でかまいません。
char型の1要素のサイズは、常に sizeof(char) です。
HspVarChar_GetUsing
varuse()が返す値を設定します。
char型の場合、「無効」になることがないので、常に真値を返します。
後述の support メンバに HSPVAR_SUPPORT_VARUSE を設定したときにのみ有効です。
HspVarChar_GetBlockSize
指定した数の要素が使うサイズを返します。
基本的によく分からない関数です。(おい)
サンプルからコピー&ペーストということで。
HspVarChar_AllocBlock
今回はなにもしません。

※これらとSet以降の関数以外は、今回は不必要。

ふぅ、1つ1つは難しくなさそうですね。
早速始めましょう!


関数を書く #0

まず、Alloc()とFree()です。
これらが一番重要なので、最初に書きましょう。

今回の char 型の仕様では、PVal構造体の pt メンバ(char*)をそのまま、char型の配列として使います。
こうすれば、管理もアクセスも簡単ですし、わかりやすいです。
そのため、Alloc()の方では、pt に hspmalloc() で確保したメモリへのポインタを格納しています。

CalcVarSize_Char()は、次のように実装します。

まぁ、見た感じの通りです。
配列の全要素数を計算し、全体に必要なバイト数を返します。

さて、続いて Cnv() と CnvCustom() 関数です。
これがなければ新しい型を使う意味がないですね。
基本的には、doublestrint の3つだけに対応すればいいでしょう。
それ以外の型には変換のしようがないので。

変換後はポインタを返すので、static な変数が型ごとに必要です。
また、char → charの変換も出来るように、一応サポートした方がいい気がします。
HSPVAR_FLAG_CHAR は、HSPVAR_FLAG_INT と同じようなものですが、これは変数です。
そのため、case に指定できません。( case には定数式しか書けないため )

続いて、GetPtr()です。実体は pt が指す領域なので、それへのポインタを返すようにします。

以前言いましたが、pval->offset は APTR 値です。

残りはほぼサンプルのままでいいので、一気に全部いきます。


関数を書く #1

次に、演算のための関数です。( Set() 以降 )
char 同士の演算は C++ でできるので、基本的にその機能を使います。

※テンプレート関数を使ってまとめたほうがいいですが、難しくなるのでやめておきました。

pdat が左辺、val や in が右辺です。
どれも pdat に計算後の値を格納していますね。
なお、両辺の型は常に一致しています。

g_pHvpChar は、char型のHspVarProc構造体へのポインタです。詳しくは後述。
g_pHvpChar->aftertype は、演算後の値の型です。
例えば、== や > などの比較では、必ず int 型の値を返すので、aftertype メンバに HSPVAR_FLAG_INT をセットしています。
型が変わらず、char型のままの場合、HSPVAR_FLAG_CHAR の代入を省略できるかどうかは分かりません。(おい)
…… だってドキュメントに書いてないんだもーん。


関数を書く #2

最後に、これらの関数を HspVarProc 構造体にセットする関数が必要です。
ここでは、HspVarChar_Init()とします。これは HspVarProc* を引数に取る関数です。

※ここで代入していない関数を呼び出そうとすると、「サポートされない機能を選択しました」というエラーが起きます。ぬるぽの心配はいりません。

を、それぞれ設定します。version は 0x001 で OK な模様。

support は、HSPVAR_SUPPORT_* という定数を、演算子 | で結合して複数指定します。

#define HSPVAR_SUPPORT_STORAGE     0x0001	// 固定長ストレージサポート
#define HSPVAR_SUPPORT_FLEXSTORAGE 0x0002	// 可変長ストレージサポート
#define HSPVAR_SUPPORT_FIXEDARRAY  0x0004	// 配列サポート
#define HSPVAR_SUPPORT_FLEXARRAY   0x0008	// 可変長配列サポート
#define HSPVAR_SUPPORT_ARRAYOBJ    0x0010	// 連想配列サポート
#define HSPVAR_SUPPORT_FLEXSIZE    0x0020	// 要素ごとのデータが可変長
#define HSPVAR_SUPPORT_NOCONVERT   0x0040	// 代入時の型変換を無効にする
#define HSPVAR_SUPPORT_VARUSE      0x0080	// varuse関数のチェックを有効にする
#define HSPVAR_SUPPORT_TEMPVAR     0x0100	// テンポラリ変数として使用する
#define HSPVAR_SUPPORT_USER1       0x4000	// ユーザーフラグ1
#define HSPVAR_SUPPORT_USER2       0x8000	// ユーザーフラグ2

※引用元は「hspvar_core.h」。


vp_char.h

ここまでの関数を vp_char.cpp に納めて、それのヘッダを書いておきます。
必要なのは HspVarChar_Init() だけなので、それを宣言するだけです。


dllmain_cpp

今回は命令も関数も使わないので、メインのファイルは以下の通りです。

char型を登録する必要があるので、hsp3hpi_init()関数が若干違います。

registvar()関数で、変数型を新たに登録します。
ちなみに、第一引数を -1 ではなく既存の HSPVAR_FLAG_* にすると、HspVarProc を上書きできます。


完成だ!! #0

ふう、ひとまず完成です。長かったですねー……。
さて、いつも通りヘッダファイルを書きますか。

// char - public header

#ifndef IG_CHAR_HPI_AS
#define IG_CHAR_HPI_AS

#regcmd "_hsp3hpi_init@4", "char.hpi", 1

// サンプル・スクリプト
#if 1

	dimtype c, vartype("char"), 3	// 配列にしてみる
	c = 'A'		// 1 の文字コード
	
	mes c		// char->str
	stop
	
#endif

#endif

…………。
………………。あれ?
char → strはうまくいっているはずなのに、画面には「64」が……?

と、デバッグウィンドウを見たら、変数 c は int 型になってますね!
そうか、'A'int なのか。
だから、代入した時点でintに変換されて……。

……というわけで、今の時点では char 型は全くもって無意味です。
ふぅ、どうなるのやら、乞うご期待。


おわりに

この話は複数回に分けてお送りします。
次回でしっかり char が使えるようになります。大変だ……。

では、また次回。


by 上大

第七章へ   第八章2へ