2010.02.12

手持ち140円がほぼ全財産となる。石油も無くなり、米も無くなりドッグフードでも食べるしか
ないのか?(犬はドッグフードを食わないので3年くらい真空パックで残っているのだった)
と思い詰めていた折、某所より1本の電話が掛かってきた。

内容は
以前作成したシナリオのキャラクタと台詞をコンバートしてほしいとのこと。

当時はせいぜい100本もいかないシナリオだし
1日アルバイトのつもりで安請け合いした。
ところが
送られてきたファイルはアーカイブで1メガ近くある。。。

半ば震える指で解凍してみるとなんと1000本以上あるではないか。ぐはっっっっっ

まぁそういうことは良くあるものである。。。あうぅぅぅ。

最初はエディターを使ってみたが何分細かいのとファイルがあまりに
多すぎるのでプログラムする事にした。
#まともにやってたら気が狂いそうだ

さて、バッチでコマンドラインに渡すかファイルダイアログを起動するかダイアログにするか
迷ったけど とりあえずI/FはダイアログベースでエクスプローラーからD&Dする方法にした。

ダイアログベースでD&Dする方法は3つおまじないが必要である
1.ダイアログクラスにOnDropFiles()を宣言する。
2. ダイアログクラスにON_WM_DROPFILES()のメッセージをマップする 。
3.OnDropFiles()を実装する。
これでダイアログにD&D可能になる。

さて、今度はコンバータ本体を作成しよう。

関数名はvoid scenarioConv(char *filename)とした。 先頭小文字で始まっているのは
MSの規約違反だがあくまでローカルのしかもスポットでしか使わないものなので
このようにしてある。
#そのへんは個人仕様なのでなぁなぁでみてほしい。

シナリオのルール #都合上あまり公にはできないのでかなり端折っています
キャラクターのコメントが始まる箇所と終了する箇所は[]でくくりINとENDが必ず対に
なる。

「雄一」というキャラクタのシナリオに入った場合
[雄一 IN]
 この間台詞
[雄一 END]
その間他のキャラクタのシナリオが入る事はない。

今回はさらに台詞も変更しなくてはならない。まぁこれは口調を変えるだけなので
変わる部分をインプリメントすればokだ。

キャラクタの変更
雄一 -> やすお
みゆき -> あんず
やすおの台詞の時 僕->自分 なんだ->です だから->ですから
あんずの台詞の時 わたし->あたし だって->だからぁ

とりあえず上記のパターンを試作。

アウトラインをインプリメント

#define STR_SRCFILE_EXT ".snr" //シナリオファイルの拡張子
#define LEN_SRCFILE_EXT sizeof(STR_SRCFILE_EXT)
#define STR_DSTFILE_EXT ".snx" //変換ファイルの拡張子
#define LEN_DSTFILE_EXT sizeof(STR_DSTFILE_EXT)


#define YUITI_IN_STR "[雄一 IN]"
#define YUITI_IN_LEN sizeof(YUITI_IN_STR)
#define YUITI_END_STR "[雄一 END]"
#define YUITI_END_LEN sizeof(YUITI_END_STR)
#define MIYUKI_IN_STR "[みゆき IN]"
#define MIYUKI_IN_LEN sizeof(MIYUKI_IN_STR)
#define MIYUKI_END_STR "[みゆき END]"
#define MIYUKI_END_LEN sizeof(MIYUKI_END_STR)

//クラス宣言
//キャラクタのコンバート

//雄一
class Yuiti{
public:
   BOOL isChange(char *bp);//TRUE:雄一のシナリオに入った時
   void Conv(FILE *srcFp,FILE *dstFp);// 雄一のシナリオに入ったら実行させる
};

//みゆき
class Miyuki{
public:
   BOOL isChange(char *bp);//TRUE:みゆきのシナリオに入った時
   void Conv(FILE *srcFp,FILE *dstFp); //みゆきのシナリオに入ったら実行
};

//クラス内関数のアウトライン
//キャラクタ毎の台詞の変更
BOOL Yuiti::isChange(char *bp){
   BOOL bRet=FALSE;
   return(bRet);
}
void Yuiti::Conv(FILE *srcFp,FILE *dstFp){
}

BOOL Miyuki::isChange(char *bp){
   BOOL bRet=FALSE; return(bRet);
}

void Miyuki::Conv(FILE *srcFp,FILE *dstFp){
}

//コンバーター入口のアウトライン
void scenarioConv(char *filename){
}

 

////////////////////////////////////////////////////////////////////////

上記アウトラインの詳細を実装

ダイアログにコメント用リストボックスを付加

以下完成

/////////////////////////////////////////////////////////////////////////////////
//シナリオコンバータサンプル
/////////////////////////////////////////////////////////////////////////////////
//今回のシナリオで改行は= 0x0d+0x0a の2バイト
//ファイルエンドは基本的に[EOF]なし
#define MAX_FILE_BUFFER 1024//ファイルの読み込みバッファ最大数
#define CNVSTACK_MAX 256//インデントの入れ子最大値

#define STR_SRCFILE_EXT ".snr" //シナリオファイルの拡張子
#define LEN_SRCFILE_EXT (sizeof(STR_SRCFILE_EXT)-1)
#define STR_DSTFILE_EXT ".snx" //変換ファイルの拡張子
#define LEN_DSTFILE_EXT (sizeof(STR_DSTFILE_EXT)-1)

#define YUITI_IN_STR "[雄一IN]"
#define YUITI_IN_LEN (sizeof(YUITI_IN_STR)-1)
#define YUITI_END_STR "[雄一 END]"
#define YUITI_END_LEN (sizeof(YUITI_END_STR)-1)
#define YUITI_CHG_IN_STR "[やすお IN]"
#define YUITI_CHG_IN_LEN (sizeof(YUITI_CHG_IN_STR)-1)
#define YUITI_CHG_END_STR "[やすお END]"
#define YUITI_CHG_END_LEN (sizeof(YUITI_CHG_END_STR)-1)

#define YUITI_TKN0_STR "雄一"
#define YUITI_TKN0_LEN (sizeof(YUITI_TKN0_STR)-1)
#define YUITI_CNV0_STR "やすお"
#define YUITI_CNV0_LEN (sizeof(YUITI_CNV0_STR)-1)

#define YUITI_TKN1_STR "僕"
#define YUITI_TKN1_LEN (sizeof(YUITI_TKN1_STR)-1)
#define YUITI_CNV1_STR "自分"
#define YUITI_CNV1_LEN (sizeof(YUITI_CNV1_STR)-1)

#define YUITI_TKN2_STR "なんだ"
#define YUITI_TKN2_LEN (sizeof(YUITI_TKN2_STR)-1)
#define YUITI_CNV2_STR "です"
#define YUITI_CNV2_LEN (sizeof(YUITI_CNV2_STR)-1)

#define YUITI_TKN3_STR "だから"
#define YUITI_TKN3_LEN (sizeof(YUITI_TKN3_STR)-1)
#define YUITI_CNV3_STR "ですから"
#define YUITI_CNV3_LEN (sizeof(YUITI_CNV3_STR)-1)


#define MIYUKI_IN_STR "[みゆき IN]"
#define MIYUKI_IN_LEN (sizeof(MIYUKI_IN_STR)-1)
#define MIYUKI_END_STR "[みゆき END]"
#define MIYUKI_END_LEN (sizeof(MIYUKI_END_STR)-1)
#define MIYUKI_CHG_IN_STR "[あんず IN]"
#define MIYUKI_CHG_IN_LEN (sizeof(MIYUKI_CHG_IN_STR)-1)
#define MIYUKI_CHG_END_STR "[あんず END]"
#define MIYUKI_CHG_END_LEN (sizeof(MIYUKI_CHG_END_STR)-1)

#define MIYUKI_TKN0_STR "みゆき"
#define MIYUKI_TKN0_LEN (sizeof(MIYUKI_TKN0_STR)-1)
#define MIYUKI_CNV0_STR "あんず"
#define MIYUKI_CNV0_LEN (sizeof(MIYUKI_CNV0_STR)-1)

#define MIYUKI_TKN1_STR "わたし"
#define MIYUKI_TKN1_LEN (sizeof(MIYUKI_TKN1_STR)-1)
#define MIYUKI_CNV1_STR "あたし"
#define MIYUKI_CNV1_LEN (sizeof(MIYUKI_CNV1_STR)-1)

#define MIYUKI_TKN2_STR "だって"
#define MIYUKI_TKN2_LEN (sizeof(MIYUKI_TKN2_STR)-1)
#define MIYUKI_CNV2_STR "だからぁ"
#define MIYUKI_CNV2_LEN (sizeof(MIYUKI_CNV2_STR)-1)

//キャラクタのコンバート
//雄一
class Yuiti{
public:
    BOOL isChange(char *bp);//TRUE:雄一のシナリオに入った時
    int Conv(FILE *dstFp,char *rbuf);//-1:なら「雄一」の終了
};

//みゆき
class Miyuki{
public:
    BOOL isChange(char *bp);//TRUE:みゆきのシナリオに入った時
    int Conv(FILE *dstFp,char *rbuf);//-1:なら「みゆき」の終了
};


//キャラクタ毎の台詞の変更
BOOL Yuiti::isChange(char *bp){
BOOL bRet=FALSE;
    if(0==memcmp(bp,YUITI_IN_STR,YUITI_IN_LEN)){
        bRet=TRUE;
    }
return(bRet);
}

int Yuiti::Conv(FILE *dstFp,char *rbuf){
int nRet=0;
    if(0==memcmp(rbuf,YUITI_IN_STR,YUITI_IN_LEN)){//「雄一 IN」
        fwrite(YUITI_CHG_IN_STR,YUITI_CHG_IN_LEN,1,dstFp);
        fwrite("\x0d\x0a",1,2,dstFp);//改行+LF
    }else
    if(0==memcmp(rbuf,YUITI_END_STR,YUITI_END_LEN)){//「雄一 END」
        fwrite(YUITI_CHG_END_STR,YUITI_CHG_END_LEN,1,dstFp);
        fwrite("\x0d\x0a",1,2,dstFp);//改行+LF
        nRet=-1;
    }else{//台詞の変換
        char wbuf[MAX_FILE_BUFFER];
        char *pSrc;
        char *pDst;
        memset(wbuf,0,MAX_FILE_BUFFER);
        pDst=&wbuf[0];
        pSrc=rbuf;
        for(int i=0;i< MAX_FILE_BUFFER;++i){
            if(0==memcmp(pSrc,YUITI_TKN0_STR,YUITI_TKN0_LEN)){
                memcpy(pDst,YUITI_CNV0_STR,YUITI_CNV0_LEN);
                pSrc += YUITI_TKN0_LEN;
                pDst += YUITI_CNV0_LEN;
            }else
            if(0==memcmp(pSrc,YUITI_TKN1_STR,YUITI_TKN1_LEN)){
                memcpy(pDst,YUITI_CNV1_STR,YUITI_CNV1_LEN);
                pSrc += YUITI_TKN1_LEN;
                pDst += YUITI_CNV1_LEN;
            }else
            if(0==memcmp(pSrc,YUITI_TKN2_STR,YUITI_TKN2_LEN)){
                memcpy(pDst,YUITI_CNV2_STR,YUITI_CNV2_LEN);
                pSrc += YUITI_TKN2_LEN;
                pDst += YUITI_CNV2_LEN;
            }else
            if(0==memcmp(pSrc,YUITI_TKN3_STR,YUITI_TKN3_LEN)){
                memcpy(pDst,YUITI_CNV3_STR,YUITI_CNV3_LEN);
                pSrc += YUITI_TKN3_LEN;
                pDst += YUITI_CNV3_LEN;
            }else{
                *pDst = *pSrc;
                ++pSrc;
                ++pDst;
            }
            if(0== *pSrc){
                break;
            }
        }
        int nLen = strlen(wbuf);
        fwrite(wbuf,sizeof(char),nLen,dstFp);
    }
return(nRet);
}







BOOL Miyuki::isChange(char *bp){
BOOL bRet=FALSE;
    if(0== memcmp(bp,MIYUKI_IN_STR,MIYUKI_IN_LEN)){
        bRet=TRUE;
    }
return(bRet);
}

int Miyuki::Conv(FILE *dstFp,char *rbuf){
int nRet=0;
    if(0==memcmp(rbuf,MIYUKI_IN_STR,MIYUKI_IN_LEN)){//「みゆき IN」
        fwrite(MIYUKI_CHG_IN_STR,MIYUKI_CHG_IN_LEN,1,dstFp);
        fwrite("\x0d\x0a",1,2,dstFp);//改行+LF
    }else
    if(0==memcmp(rbuf,MIYUKI_END_STR,MIYUKI_END_LEN)){//「みゆき END」
        fwrite(MIYUKI_CHG_END_STR,MIYUKI_CHG_END_LEN,1,dstFp);
        fwrite("\x0d\x0a",1,2,dstFp);//改行+LF
        nRet=-1;
    }else{//台詞の変換
        char wbuf[MAX_FILE_BUFFER];
        char *pSrc;
        char *pDst;
        memset(wbuf,0,MAX_FILE_BUFFER);
        pDst=&wbuf[0];
        pSrc=rbuf;
        for(int i=0;i< MAX_FILE_BUFFER;++i){
            if(0==memcmp(pSrc,MIYUKI_TKN0_STR,MIYUKI_TKN0_LEN)){
                memcpy(pDst,MIYUKI_CNV0_STR,MIYUKI_CNV0_LEN);
                pSrc += MIYUKI_TKN0_LEN;
                pDst += MIYUKI_CNV0_LEN;
            }else
            if(0==memcmp(pSrc,MIYUKI_TKN1_STR,MIYUKI_TKN1_LEN)){
                memcpy(pDst,MIYUKI_CNV1_STR,MIYUKI_CNV1_LEN);
                pSrc += MIYUKI_TKN1_LEN;
                pDst += MIYUKI_CNV1_LEN;
            }else
            if(0==memcmp(pSrc,MIYUKI_TKN2_STR,MIYUKI_TKN2_LEN)){
                memcpy(pDst,MIYUKI_CNV2_STR,MIYUKI_CNV2_LEN);
                pSrc += MIYUKI_TKN2_LEN;
                pDst += MIYUKI_CNV2_LEN;
            }else{
                *pDst = *pSrc;
                ++pSrc;
                ++pDst;
            }
            if(0== *pSrc){
                break;
            }
        }
        int nLen = strlen(wbuf);
        fwrite(wbuf,sizeof(char),nLen,dstFp);
    }
return(nRet);
}




//コンバーター入口の実装
void CStrConvDlg::scenarioConv(char *filename){
CString msg;
char dstFname[_MAX_PATH];
char *bp;
int nExtpos;
    memset(dstFname,0,_MAX_PATH);//変更後のファイル名を初期化
    bp=filename;
    nExtpos=strlen(bp) - LEN_SRCFILE_EXT;
    if(5>nExtpos){//あり得ないが念のため
        msg.Format("SrcError>[%s]",filename);
        m_Listbox.AddString(msg);
    }else{
        //変換対象ファイル?
        if(0 == memcmp(&filename[nExtpos],STR_SRCFILE_EXT,LEN_SRCFILE_EXT)){
            //変換ファイル名を作成
            memcpy(dstFname,filename,nExtpos);
            memcpy(&dstFname[nExtpos],STR_DSTFILE_EXT,LEN_DSTFILE_EXT);
            FILE *srcFp;
            FILE *dstFp;
            char rbuf[MAX_FILE_BUFFER];
            srcFp=fopen(filename,"rb");
            if(srcFp){
                dstFp=fopen(dstFname,"wb");
                if(dstFp){
                    class Yuiti CYuiti;
                    class Miyuki CMiyuki;
                    int nConverting =0;
                    char indentstack[CNVSTACK_MAX];
                    memset(indentstack,0,CNVSTACK_MAX);
                    msg.Format("IN >[%s]",filename);
                    m_Listbox.AddString(msg);
                    while(1){
                        int nReadBytes =0;
                        memset(&rbuf[0],0,MAX_FILE_BUFFER);
                        int nRet= oneLineread(srcFp , &rbuf[0],&nReadBytes);

                        if(0 < nReadBytes)
                            if(CYuiti.isChange(rbuf)){
                                ++nConverting;
                                if(CNVSTACK_MAX == nConverting){
                                    nConverting = CNVSTACK_MAX - 1;
                                    msg.Format("スタックオーバー>[%s]",filename);
                                    m_Listbox.AddString(msg);
                                }
                                indentstack[nConverting] = 1;//雄一のシナリオ中
                            }else
                            if(CMiyuki.isChange(rbuf)){
                                ++nConverting;
                                if(CNVSTACK_MAX == nConverting){
                                    nConverting = CNVSTACK_MAX - 1;
                                    msg.Format("スタックオーバー>[%s]",filename);
                                    m_Listbox.AddString(msg);
                                }
                                indentstack[nConverting] = 2;//みゆきのシナリオ中
                            }
                            switch(indentstack[nConverting]){
                            case 1:if(-1 == CYuiti.Conv(dstFp,rbuf)){
                                        //雄一のシナリオ終了
                                        indentstack[nConverting] =0;
                                        --nConverting;
                                        if(0> nConverting){
                                            nConverting = 0;
                                            msg.Format("インデントエラー>[%s]",filename);
                                            m_Listbox.AddString(msg);
                                        }
                                 }
                                break;
                            case 2:if(-1 == CMiyuki.Conv(dstFp,rbuf)){
                                        //みゆきのシナリオ終了
                                        indentstack[nConverting] =0;        
                                        --nConverting;
                                        if(0> nConverting){
                                            nConverting = 0;
                                            msg.Format("インデントエラー>[%s]",filename);
                                            m_Listbox.AddString(msg);
                                        }
                                 }

                                break;
                            default:fwrite(rbuf,1,nReadBytes,dstFp);break;
                            }
                        }
                        if(0 == nReadBytes){//読めなかったら終了
                            break;
                        }else
                        if((-1) == nRet){//エラーなら終了
                            break;
                        }else
                        if((-2) == nRet){//ファイルエンドで終了
                            break;
                        }else
                        if((-3) == nRet){//ファイルエンドで終了
                            break;
                        }
                    }
                    fclose(dstFp);
                    msg.Format("OUT<[%s]",filename);
                    m_Listbox.AddString(msg);
                }else{
                    msg.Format("DstOpenError>[%s]",dstFname);
                    m_Listbox.AddString(msg);
                }
                fclose(srcFp);
            }else{
                msg.Format("SrcOpenError>[%s]",filename);
                m_Listbox.AddString(msg);
            }
        }else{
            msg.Format("対象外>[%s]",filename);
            m_Listbox.AddString(msg);
        }
    }
}

// -2:ファイルエンド[EOF] *pnReadが1の場合[EOF]のみ
// -3:ファイルエンド[EOF][LF]なしで終了
// -4:*pnReadが1の場合[LF]のみ *pnReadが2の場合[改行+LF] *pnReadが3以上の場合
// コメント+[LF]or[改行+LF]
// -1:その他エラー
int CStrConvDlg::oneLineread(FILE *fp,char *dst,int *pnRead)
{
int nRet=-1;
    for(int i=0;i< MAX_FILE_BUFFER;++i){
        size_t n=fread(dst,1,1,fp);
        if(1== n){
            ++ *pnRead;
            nRet = 0;
        }else{//No more Read
            nRet = -3;
            break;
        }
        if(0x1a == (int)*dst){//[EOF]
            nRet=-2;
            break;
        }
        if(0x0a == (int)*dst){//[LF]
            nRet = -4;
            break;
        }
        ++dst;
    }
return(nRet);
}

プログラムはこちら

SEO [PR] 爆速!無料ブログ 無料ホームページ開設 無料ライブ放送