概要
このシリーズはHSPの.ax
ファイルの作成をするhspcmpを読んでいくものです。
わかったことをどんどん書き込んでいくスタイルでいきます。
間違いに気づいた方や、加筆すべきポイントを見つけた人はコメントで指摘してください。
あとここに掲載されたコードは
Hot Soup Processor (HSP) / OpenHSP Copyright (c) 1997-2020, onion software/onitama in collaboration with Sencha, Yume-Yume Yuuka, Y-JINN, chobin, Usuaji, Kenji Yuukoku, puma, tom, sakura, fujidig, zakki, naznyark, Lonely Wolf, Shark++, HyperPageProject, Chokuto, S.Programs, Yuki, K-K, USK, NGND001, yoshis, naka, JET, eller, arue, mjhd_otsuka, tds12 All rights reserved.
から一部改変したものです。
必要に応じて元のコードからインデントを調整したり、コメントや空行を省いています。
あと、これは2023/06/23時点のコードになります。
以前別名義で投稿していたものをほぼそのまま再投稿したものです。
またこれらのコードはOpenHSP 3.6のコードに基づいているため、3.6正式版や最新(3.7β)のものと異なる可能性があることに注意してください。
membuf.cpp(membuf.h)
hspcmp.exe内で文字列を扱うためのバッファとして使われています。
また、使い方には大きく分けて以下の3つがあります。
- プリプロセスするファイルの格納
- プリプロセスとコンパイル時のメッセージの格納
- 生成する
.ax
ファイルの格納
今回はこの3つの使い方のうち、上二つに関係するメソッドなどを紹介します。
CMemBufクラス
これがmembuf.cpp/hの本体です。
フィールド(一部)
- int limit_size
-
PreparePtrメソッドで拡張される分。値は
0x1000
か0x4000
か0x10000
のどれかになる。
-
PreparePtrメソッドで拡張される分。値は
- int size
-
mem_buf
のバッファサイズ。
-
- int cur
-
mem_buf
の使用(予約)済みのバッファサイズ。size
を超えそうになったらPreparePtrメソッドでmem_buf
が拡張されます。
-
- char *mem_buf
-
CMenBuf
のメインバッファ
-
- char name[256]
- 解析されるファイル名
コンストラクタ
2種類のコンストラクタがありますが、mem_buf
フィールドのバッファサイズを4KBか16KBか64KBで初期化するように引数を取っているだけで、初期化の処理はInitMenBufメソッドに丸投げしています。
引数(一つ目の方)
なし
コードを見てみる(一つ目の方)
CMemBuf::CMemBuf( void )
{
InitMemBuf( 0x10000 );
}
mem_buf
フィールドのバッファサイズを64KBで初期化します。
引数(二つ目の方)
- int sz
-
mem_buf
フィールドを何byte分確保するか。結局4,16,64KBをしきい値にした値になる。最大で64KBになる。
-
コードを見てみる(二つ目の方)
CMemBuf::CMemBuf( int sz )
{
InitMemBuf( sz );
}
mem_buf
フィールドのバッファサイズをsz
byte(4,16,64KBをしきい値にして変更される)で初期化します。
InitMemBufメソッド
ここでフィールドが初期化されます。
引数
- int sz
-
mem_buf
フィールドを何byte分確保するか。結局4,16,64KBをしきい値にした値になる。最大で64KBになる。
-
コードを見てみる
void CMemBuf::InitMemBuf( int sz )
{
size = sz;
if ( size<0x1000 ) {
size = 0x1000;
} else if ( size<0x4000 ) {
size = 0x4000;
} else {
size = 0x10000;
}
ここでは、size
フィールドにsz
を代入してからsize
の値によってsize
を4,16,64KBのきりがいい値に変更しています。
limit_size = size;
mem_buf = (char *)malloc( limit_size );
mem_buf[0] = 0; name[0] = 0; cur = 0;
idxflag = 0; idxmax = -1; curidx = 0; idxbuf = NULL;
}
ここでフィールドを初期化しています。それぞれがどの値に初期化されるかはコードを見てください。
デストラクタ
ここで、mem_buf
をfree
を使って解放しています。
コードはみません。
PreparePtrメソッド
mem_buf
を引数で指定した分だけ使うときに、必要ならばmem_buf
をlimit_size
byte拡張します。その後、mem_buf
で使用されていない部分の一番最初へのポインタが返されます。
また、このメソッドの性質上mem_buf
に文字を書き込む際は必ず呼び出されます。
引数
- int sz
-
mem_buf
を何byte使いたいか。
-
使われている変数
- int i
-
mem_buf
を拡張しなければならないときの新しいmem_buf
のバッファサイズ
-
- char *p
- PreparePtrメソッドの返り値を保存します。
コードを見てみる
char *CMemBuf::PreparePtr( int sz )
{
int i;
char *p;
if ( (cur+sz) < size ) {
p = mem_buf + cur;
cur += sz;
return p;
}
ここでは、sz
の分だけ使っても構わないとき、p
にmem_buf
の最後の文字のポインタを代入し、cur += sz
してp
を返しています。
i = size;
while( i<=(cur+sz) ) i+=limit_size;
ここからはsz
文だけ使おうとするとmem_buf
がオーバーフローすることになるので、mem_buf
を拡張します。
ここでは、mem_buf
のサイズがどれほど必要なのかを計算しています。また、切りよくするためか拡張する際はlimit_size
分だけ拡張するようになっています。
p = (char *)malloc( i );
memcpy( p, mem_buf, size );
free( mem_buf );
size = i;
mem_buf = p;
p = mem_buf + cur;
cur += sz;
return p;
}
ここでは、拡張後のサイズ(i
)がわかったのでp
をいったんi
だけ確保してからmem_buf
をコピーして、その後mem_buf
にP
を代入するといった形になっています。
あとは、sz
の分だけ使っても構わないときと同じ処理をして終わります。
Putメソッド
引数で指定したデータをmem_buf
に書き込みます。
引数の種類によってたくさんあるのでそれぞれについて書きませんが、動作原理としては
-
char *p
を用意する。 - 引数のデータサイズを指定したPreparePtrメソッドを呼び出し、帰ってきたポインタを
p
に代入。 -
p
にmemcpy
などを使って引数で指定したデータを書き込む。
となります。
どのように実装されているかが気になる人はOpenHSP/src/hspcmp/membuf.cppを見てください。
PutStrメソッド
これもPutメソッドと同じように動作します。
引数
- char *data
-
mem_buf
に書き込む文字列
-
使われている変数
- char *p
- PreparePtrメソッドの返り値を保存します。
コードを見てみる
void CMemBuf::PutStr( char *data )
{
char *p;
p = PreparePtr( strlen(data) );
strcpy( p, data );
}
まあ前述のPut
メソッドとの違いは、p
にdata
書き込むときにstrcpy
を使っているぐらいの違いしかありません。
PutStrBlockメソッド
PutStrメソッドとほぼ同じです。
引数
- char *data
-
mem_buf
に書き込む文字列
-
使われている変数
PutStrメソッドと同じ
コードを見てみる
void CMemBuf::PutStrBlock( char *data )
{
char *p;
p = PreparePtr( strlen(data)+1 );
strcpy( p, data );
}
PutStrメソッドとの違いは、書き込める文字数を一文字分多くしています。
なぜこんなことをしているのかは不明。(Additional HSP Template & Toolsと関係ありそう。)
PutCRメソッド
mem_buf
に\r\n
を追加します。
使われている変数
PutStrメソッドと同じ
コードを見てみる
void CMemBuf::PutCR( void )
{
char *p;
p = PreparePtr( 2 );
*p++ = 13; *p++ = 10;
}
PreparePtrメソッドでmem_buf
に必要があれば2文字分確保してから、\r
(13)と\n
(10)を書き込みます。
PutDataメソッド
受け取ったポインタをchar
のポインタにキャストして、指定文字数分だけmem_buf
に代入します。
引数
- void *data
-
mem_buf
に書き込むデータ
-
- int sz
-
mem_buf
に書き込む文字数
-
使われている変数
PutStrメソッドと同じ
コードを見てみる
void CMemBuf::PutData( void *data, int sz )
{
char *p;
p = PreparePtr( sz );
memcpy( p, (char *)data, sz );
}
PreparePtrメソッドでsz
分だけ必要があればmem_buf
を拡張して、memcpy
でdata
をsz
だけp
に書き込みます。
PutStrfメソッド
フォーマット指定子を使った文字列をmem_buf
に書き込みます。
引数
- char *format
- フォーマット指定子付き文字列
- 可変長引数(
...
)- フォーマットをする変数たち
使われている変数
- va_list args
- フォーマットをする変数たちが格納される?
- int c
- int space
- char *p
- int n
コードを見てみる
#if ( WIN32 || _WIN32 ) && ! __CYGWIN__
# define VSNPRINTF _vsnprintf
#else
# define VSNPRINTF vsnprintf
#endif
ここではVSNPRINTF
を、Windows(Cygwinではない)なら_vsnprintf
とし、それ以外(Linux)ならvsnprintf
としています。
void CMemBuf::PutStrf( char *format, ... )
{
va_list args;
int c = cur;
int space = size - cur;
ここで使う変数を一部定義しています。c
はcur
(mem_buf
のインデックス)を、space
はmem_buf
の残りバッファを示します。
while(1) {
char *p = PreparePtr(space - 1);
cur = c;
space = size - cur;
ここでp
にmem_buf
を割り当ててcur
をもと(c
)に戻しています。
そして、space
にはmembuf
に書き込める文字数が代入されることになります。
int n;
va_start(args, format);
n = VSNPRINTF(p, space, format, args);
va_end(args);
ここで、フォーマットに成功すればformat
にフォーマットされた文字列が代入されて、n
にその文字数が代入されて、失敗すればn
に-1
が代入されます。
if ( 0 <= n && n < space ) {
cur += n;
return;
}
if ( 0 <= n ) {
space = n + 1;
} else {
space *= 2;
}
}
}
ここでn
の値に応じて繰り返したり、処理を終了したりします。
PutFileメソッド
引数で指定したファイルが存在すればmem_buf
にファイルの内容を書き込みます。
ファイルが存在しない場合は-1
が、ファイルが存在した場合はファイルサイズ(ファイルの文字数)が帰ります。
引数
- char *fname
-
mem_buf
に書き込みたいファイルのパス。
-
使われている変数
- char *p
- PreparePtrメソッドの返り値を保存します。
- int length
- ファイルサイズ(ファイルの文字数)
- FILE *ff
- ファイルを操作するときに必要な奴(C#でいうところの
Stream
に近い)
- ファイルを操作するときに必要な奴(C#でいうところの
コードを見てみる
変数の定義箇所は省略します。
int CMemBuf::PutFile( char *fname )
{
//変数の定義箇所とコメントは省略
ff=fopen( fname,"rb" );
if (ff==NULL) return -1;
fseek( ff,0,SEEK_END );
length=(int)ftell( ff );
fclose(ff);
if (length < 0) return -1;
ここでファイルが存在するかどうかを調べて、存在した場合はlength
にファイルサイズ(ファイルの文字数)が代入され、存在しなければ-1
で返ります。
p = PreparePtr( length+1 );
ff=fopen( fname,"rb" );
fread( p, 1, length, ff );
fclose(ff);
p[length]=0;
ここで、PreparePtrメソッドで必要であればmem_buf
をlength
だけ拡張して、p
にmem_buf
のポインタを割り当てて、fread
で読み取ったファイル内容をp
(mem_buf
)に書き込んでます。
そして、終端ヌル文字を代入しています。
strcpy( name,fname );
return length;
}
最後にname
にファイル名を書き込んで、length
を返します。
次は
次回は、membuf.cpp/.hの残りを解説します。
hspcmp(exe版)のコードを読む 2-2 ~membuf.cpp/.h編~