// makoto.cpp : DLL アプリケーション用のエントリ ポイントを定義します。 // // Ver.1.02 文字化けを修正 // // Ver.1.01 makoto0.lst,makoto1.lst でコメント以外の // コンマが無い行以降を読み込まない不具合を修正 // Ver.1.0 初期バージョン #include #include #include #include #define MAX_STRING_SIZE 4096 #define SAKURA_MAP_FILE "makoto0.lst" #define UNYU_MAP_FILE "makoto1.lst" #define MAKOTO_VERSION "Makoto Basic with Select and Repeat Ver. 1.02" #define CALL_VERSION_STRING "TELL_ME_MAKOTO_VERSION" #define ECH '\\' typedef struct _TranslateMap { int entryNumber; // 変換ファイルにある変換の組の数 char **fromString; // 変換ファイルにある変換対象の文字列を格納するポインタの配列 char **toString; // 変換ファイルにある変換後の文字列を格納するポインタの配列 } TranslateMap; TranslateMap sakura_tm={0}, unyu_tm={0}; // aFilnemae から makoto_basic 用のファイルを読み込み、aTmに格納する void readWordMap(char* aFilename, TranslateMap* aTm); // aTm が管理している領域を解放する void releaseTmMemory(TranslateMap* aTm); // makoto_basic の呼び出し。 文字列長aLen の aMessageに対して変換を行う char* makoto_basic(char* aMessage, int aLen); // 選択と反復関数 char* makoto_select_and_repeat(char *aMessage, int aLen) ; // 選択関数 char* makoto_select(char *aMessage, int aLen); // \(, \) などの 時に '\' を削除する char* remove_escape(char *aMessage, char aCh); extern "C" __declspec(dllexport) HGLOBAL __cdecl execute(HGLOBAL h, long *len) { char *p2; p2 = new char[*len]; memcpy(p2, h, *len); GlobalFree(h); // makoto_basic の呼び出し: p2 は関数内でdeleteされ newされる p2 = makoto_basic(p2, *len); // makoto_select_and_repeat の呼び出し: p2 は関数内でdeleteされ newされる p2 = makoto_select_and_repeat(p2, strlen(p2)); *len=strlen(p2); h = GlobalAlloc(GPTR, *len); memcpy(h, p2, *len); delete p2; return(h); } // DLL が置かれているPATHを受け取る // makoto BASIC 用のファイルを読み込む extern "C" __declspec(dllexport) BOOL __cdecl load(HGLOBAL h, long len) { srand(time(NULL)); char *dirPath = new char[len+1]; // NULL 文字用 memcpy(dirPath, (LPVOID)h, len); // PATH 名を取得 char filename[MAX_STRING_SIZE]; // あんまり長いのいれないでえ memcpy(filename, dirPath, len); // sakura memcpy(filename+len, SAKURA_MAP_FILE, strlen(SAKURA_MAP_FILE)+1); readWordMap(filename, &sakura_tm); // unyu memcpy(filename+len, UNYU_MAP_FILE, strlen(UNYU_MAP_FILE)+1); readWordMap(filename, &unyu_tm); delete dirPath; GlobalFree(h); return(TRUE); } extern "C" __declspec(dllexport) BOOL __cdecl unload() { // tm の管理している領域を解放 releaseTmMemory(&sakura_tm); releaseTmMemory(&unyu_tm); return(TRUE); } void readWordMap(char* aFilename, TranslateMap* aTm) { FILE* fp = fopen(aFilename, "r"); char line[MAX_STRING_SIZE]; // // まずエントリー数を数える // int count=0; while (fp && fgets(line, MAX_STRING_SIZE, fp)) { // skip if // or CR or LF if (line[0] == '/' &&line[1] == '/') { continue; } if (line[0] == 10 || line [0] == 13) { continue; } // find a comma and CRLF int comma = 0, crlf=0; while(line[comma] != ',' && line[comma]) comma++; while(line[crlf] != 10 && line[crlf] != 13 && line[crlf]) crlf++; if (comma >= crlf) continue; // skip if there is no comma in a line. count++; // 有効なエントリーである } // 領域を確保 aTm->entryNumber = count+1; // +1 is For Version Information aTm->fromString = new char*[count+1]; aTm->toString = new char*[count+1]; // Version 情報を変換するための文字列を入れる int len = strlen(CALL_VERSION_STRING); char *from = new char[len+1]; memcpy(from, CALL_VERSION_STRING, len); from[len]=0; len = strlen(MAKOTO_VERSION); char *to = new char[len+1]; memcpy(to, MAKOTO_VERSION, len); to[len]=0; aTm->fromString[count] = from; aTm->toString[count] = to; if (count == 0) return; ////////////// // もう一度最初から ////////////// fseek(fp, 0, SEEK_SET); count=0; // カウンタ while (fgets(line, MAX_STRING_SIZE, fp)) { // skip if // or CR or LF if (line[0] == '/' &&line[1] == '/') { continue; } if (line[0] == 10 || line [0] == 13) { continue; } // find a comma and CRLF int comma = 0, crlf=0; while(line[comma] != ',' && line[comma]) comma++; while(line[crlf] != 10 && line[crlf] != 13 && line[crlf]) crlf++; if (comma >= crlf) continue; // skip if there is no comma in a line. // // 文字列の切り出しと代入 char *from = new char[comma+1]; // NULL 文字も入れる memcpy(from, line, comma); from[comma] = 0; aTm->fromString[count] = from; char *to = new char[crlf-comma];// NULL 文字も入れる memcpy(to, line+comma+1, crlf-comma-1); to[crlf-comma-1] = 0; aTm->toString[count] = to; count++; // 有効なエントリーである } fclose(fp); } void releaseTmMemory(TranslateMap* aTm) { if (aTm->entryNumber == 0) return; for (int i=0; ientryNumber; i++) { delete aTm->fromString[i]; delete aTm->toString[i]; } delete aTm->fromString; delete aTm->toString; } char* makoto_basic(char* aMessage, int aLen) { char buf[MAX_STRING_SIZE]; int speaker = 0; // 0 is sakura, 1 is unyu bool esc = false, ene=false, replace=false; int dst=0; // buf の確定した文字列の次の位置を保持 TranslateMap *tm; // 順次走査 for (int pos=0; posentryNumber; num++) { if (pos+strlen(tm->fromString[num]) > (UINT)aLen) continue; // 長いので絶対マッチしない // 文字列一致の判定開始 bool isMatch=true; for (int i=0; (UINT)ifromString[num]); i++) { // 一致するか if (aMessage[pos+i] != tm->fromString[num][i]) { isMatch=false; break; } } // 文字列一致の判定終了 if (isMatch) { // 置換を行う。その文字列は確定される if (dst+strlen(tm->toString[num]) < MAX_STRING_SIZE) { memcpy(buf+dst, tm->toString[num], strlen(tm->toString[num])); dst += strlen(tm->toString[num]); pos += strlen(tm->fromString[num])-1; replace=true; break; } } // end if isMatch 一致しなければ何もしない } // end for num } else { //if esc switch (aMessage[pos]) { case 'h': speaker = 0; break; // 変換辞書の変更→さくら case 'u': speaker = 1; break; // 変換辞書の変更→うにゅう case 'e': ene=true; break; // えんいー 発見 default: break; } } if (!replace) { // 既に置換が発生していれば何もしない buf[dst++] = aMessage[pos]; // 一文字確定 if (aMessage[pos] == ECH) { esc=true && !esc; } else {esc=false;} // escape フラグ } if (ene || dst >= MAX_STRING_SIZE-1) break; // 終了条件 } // end for pos // 確定した文字列を戻す char *ret = new char[dst+1]; delete aMessage; memcpy(ret, buf, dst); ret[dst] = 0; return ret; } // 正規表現の逆をいく *ような* 処理を行う // ● 基本 // 選択: (A|B|C|...) ならば A,B,Cのいずれか一つが選択。各要素は等確率で選ばれる。 // ex. (です|ですわ|だい!) // 乱数回反復: (X)数字1文字。 (X)3 ならば X が 0-3 回 繰り返される。 回数は等確率で決まる。 // ex. つらいよ(〜)3 // ※)2-4 回繰り返したい時は XX(X)2 などとして下さい。 // ※)9回以上の繰り返しはできません。 // // ● 組合せ // 明日(は|って(さあ(〜)3)1|の天気は)(晴れ|雨(のち(時々|一時)1(台風|雪))1)だって(さ)1。 // // ● 展開処理の順番 // 「左からみて最初に見つけた終了括弧に対応する部分から」という感じです。 // // ● エスケープについて // 基本的に '\' でエスケープします。 '\(', '\|', '\)' は '\' が削除された文字に変換されます。 // それ以外はそのまま通過します。 '\A' '\u' などは そのままです。 // '(^^)' 等を表現したい時は、'\(^^)' です。 // '\A'もしくは'\B'という意図で、'\(A|B)' 等を表現したい時は、 '\\(A|B)' です。 // '\(^^)' 等を表現したい時は、 '\\\(^^)' となります。 // '|' は 括弧() の中でしか解釈されません。 括弧外ならば 普通に '|' を使っても大丈夫です。 // 開始括弧'(' は 終了括弧')' が無ければ普通の文字として扱われます。 // 同じく ')' は '('がなければ普通の文字として扱われます。 // 括弧の後すぐに数字を置きたい時は '(X)\3' とすればできます。 // // ● 例外 // 4096 文字(byte)(辺り)を越えたら、処理を停止し、今まで確定している文字列が返ります。 char* makoto_select_and_repeat(char *aMessage, int aLen) { int start=-1, end=-1, repeat=-1; bool esc = false; for (int cur=0; cur= '1' && aMessage[end+1] <= '9') { repeat = (int)(aMessage[end+1] - '0'); } if (aMessage[end+1] == ECH && aMessage[end+2] >= '1' && aMessage[end+2] <= '9') { // (a|b)\3 等の場合 end++; } if (repeat > 0) {// 乱数回反復 end++; repeat = rand() % (repeat+1); int len=strlen(selectString); if (len*repeat < MAX_STRING_SIZE) { char *buf = new char[len*repeat+1]; for (int i=0; i