CGI State: Sealed by Overload


はじめに

以下の文書はMakoto "Basic"オリジナルの仕様書です。
現在のゴーストの仕様と異なる部分がありますので注意してください。



トランスレータ

前提


偽春菜の構造はこう見えてかなり遠大で、スキンを変えるような感覚でセリフを変えることは不可能です。

しかしそれは一から文章を書き直す場合での話であり、必要とされる動作がもし「スキンと口調を合わせたい」という程度の要求であるなら、アプローチ次第で遙かに簡単にそしてかなり汎用性の高い方法で口調を変化させることができます。その手段の一つがトランスレータです。

仕様


トランスレータの実体は execute 関数をエクスポートする makoto.dll という DLL です。偽春菜は全てのセリフをこの関数を通したのちに喋ります。即ち、プログラマは execute 関数内で偽春菜からスクリプトを受け取り、一定の法則で変換したあと、それを偽春菜に戻せばいいわけです。

何をするかは全くの自由です。何の変換もせずに戻せば「何もしない」トランスレータということになります。


extern "C" __declspec(dllexport) HGLOBAL __cdecl execute(HGLOBAL h, long *len);
function execute(h: thandle; var len: longint): thandle; export; cdecl;


第1引数がグローバルメモリハンドル、第2引数が文字列の長さです(念のため)。

偽春菜はスクリプトを GMEM_FIXED で送ります。DLLは文字列取得後メモリを解放、文字列に対して適宜変更を行い、正しい len をセットし直し、新しい GMEM_FIXED で戻して下さい。

*

DLLロード時およびアンロード時に以下の関数が呼ばれます。


extern "C" __declspec(dllexport) BOOL __cdecl load(HGLOBAL h, long len);
function load(h: thandle; len: longint): boolean; export; cdecl;

extern "C" __declspec(dllexport) BOOL __cdecl unload();
function unload: boolean; export; cdecl;


unloadはどうでもいいですが重要なのはload時です。第1引数にDLLのディレクトリパスが渡されます。データファイル等を持つ場合はここからカレントディレクトリを取得し、そこにデータファイルを作って下さい。ホームディレクトリやwindowsディレクトリ等にデータファイルを作るのは人間的に問題があります。また必要ない場合でも関数内で必ずハンドルを解放して下さい。

戻り値はboolですが現在のところ偽春菜はこの値を見ていません(何が返ってきても処理を続行します)。

*

関数は中身を実装するか否かに関わらず必ず全てエクスポートして下さい。足りなければ暴走します。

ファイル構成


home
  +-ghost
      +-misuzu
          +-makoto.dll

注意


メインスレッドで動くので長い処理をやるとプログラム全体が重くなります。ハングアップすればプログラム全体がハングアップします。メモリ破壊等があれば本体もおかしくなります。

スケルトンソースコード


いずれも「何もしない」トランスレータです。

*

VC++

extern "C" __declspec(dllexport) HGLOBAL __cdecl execute(HGLOBAL h, long *len) {
  LPVOID p,p2;

  p=h;
  p2=malloc(*len);
  memcpy(p2,p,*len);
  GlobalFree(h);

  // ここで何かやる

  h=GlobalAlloc(GPTR,*len);
  p=h;
  memcpy(p,p2,*len);
  free(p2);

  return(h);
}

extern "C" __declspec(dllexport) BOOL __cdecl load(HGLOBAL h, long len) {
  GlobalFree(h);

  return(TRUE);
}

extern "C" __declspec(dllexport) BOOL __cdecl unload() {
  return(TRUE);
}
*

Object Pascal

function execute(h: hglobal; var len: longint): hglobal; export; cdecl;
var
  h2: hglobal;
  p: pointer;
  s: string;
begin
  p:=pointer(h);
  setlength(s,len);
  move(p^,pchar(s)^,len);
  globalfree(h);

  // ここで何かやる

  h2:=globalalloc(gptr,len);
  p:=pointer(h2);
  move(pchar(s)^,p^,len);
  result:=h2;
end;

function load(h: hglobal; len: longint): boolean; export; cdecl;
begin
  globalfree(h);

  result:=true;
end;

function unload: boolean; export; cdecl;
begin
  result:=true;
end;

簡単な方法

Makoto "Basic"


これだと誰も寄りつかない気がするのでお仕着せのトランスレータを用意しました。

このDLLは同じディレクトリにある makoto0.lst と makoto1.lst を読み、そのデータに基づいて口調を変換します。この2ファイルの構造は以下の通りです。


だよね,ですよね
るよ。,ますね。
ちゃったね,ちゃいましたね
ないけど。,ませんけど。


左の単語にマッチするものが右の単語に置換されます。makoto0.lst は本体側、makoto1.txt はうにゅう側のセリフを置換します。

この例は丁寧な口調への変換を目指していることになります。

Makoto "Basic" は再配布自由です。自由に同梱して下さい。

ファイル構成


home
  +-ghost
      +-misuzu
          +-makoto.dll
          +-makoto0.lst
          +-makoto1.lst

補足


左側しかない、あるいは右側しかない等明らかに間違った書式で書かれていたとしても、何の処置もなくただ暴走します。

空白行、あるいは先頭が // で始まる行はコメントとして扱われます。

履歴


phase 0

初版

phase 1

変換後の単語が変換前の単語を完全に含んでいると暴走するからそれを防ぐためにそういう指定を全て無視するという間抜け仕様を止める。変換後の単語が変換前の単語を完全に含んでいても正常動作するようにした。

phase 2

暗号化ファイル対応

phase 3

カンマバグ修正
バージョン情報付加

phase 4

致命的バグ修正
makoto0.lst と makoto1.lst のどちらか片方がないと両方ともロードされない問題を修正


Makoto 2.0仕様書 (現在の仕様)