CUIからGUIへ(3)

ファイル選択ダイアログ

Windows風のファイル読み書きを体験してもらったところで、今度はコモンコントロールのファイル選択ダイアログを使ってみよう。
ファイル選択ダイアログについてはhttp://wisdom.sakura.ne.jp/system/winapi/common/common6.htmlこの辺が詳しいが、これはSDK用の説明。
今回はMFCを使うのでもっと簡単に実装できる。そちらの説明はこちらhttp://www.h6.dion.ne.jp/~shiimori/mfc/mfc05.htm
ではさっそく、ダイアログにボタンを一つ追加して、OnFileSelect()というような名前の関数を生成し、コードを記述してみよう。

void CD6Dlg::OnFileSelect() 
{
	char strPath[MAX_PATH];

	CFileDialog    dlg(TRUE, NULL, NULL,
            OFN_HIDEREADONLY|OFN_FILEMUSTEXIST|OFN_NOCHANGEDIR,
            "テキストファイル(*.txt)|*.txt|全てのファイル(*.*)|*.*||",
            this);

	//  ファイルダイアログの起動
	if (dlg.DoModal() == IDOK) {
		// 選択ファイル名取得
		strcpy(strPath, dlg.GetPathName());
		MessageBox(
			TEXT(strPath) ,
			TEXT("報告") , MB_OK
		);
	}
}

このコードでは既存ファイルを選択して、そのファイルのパスをメッセージボックスで出力する。
メッセージボックスでの出力というのはへちょいので、エディットボックスを一つ作り、そこに出力するように変更したのがこちら。

void CD6Dlg::OnFileSelect() 
{
	char strPath[MAX_PATH];

	CFileDialog    dlg(TRUE, NULL, NULL,
            OFN_HIDEREADONLY|OFN_FILEMUSTEXIST|OFN_NOCHANGEDIR,
            "テキストファイル(*.txt)|*.txt|全てのファイル(*.*)|*.*||",
			this);

	//  ファイルダイアログの起動
	if (dlg.DoModal() == IDOK) {
		// 選択ファイル名取得
		strcpy(strPath, dlg.GetPathName());
		// エディットボックス(IDC_EDIT1)に得たパスをセット
		CEdit *pEdit = (CEdit *)GetDlgItem(IDC_EDIT1);
		pEdit->SetWindowText(strPath);
	}
}

改行コード変換アルゴリズム

話を改行コード変換に戻そう。
まず手始めにMacUNIX文字コードからWindows用の文字コードに変換することを考える。
具体的には以下の三通りの処理を行う。

  • \r -> \r\n
  • \n -> \r\n
  • other -> 変換しない

プログラムっぽく書けばこうなる。

int tmp = fgetc(fpIn);
switch (tmp) {
  case '\r':
  case '\n':
    fputs("\r\n", fpOut);
    break;

  default:
    fputc(tmp, fpOut);
}

これでMacUnixからWindowsへの変換は成功したが、実は問題がある。Win->Winの変換がうまくいかないのだ。
\rと\nをそれぞれ\r\nに変換するため、Windowsの改行コードである\r\nを\r\n\r\nの改行二つに変換してしまう。
読み込んだ文字が\rだった場合は次の文字が\nであるかチェックして処理を分ける必要がある。直したコードがこちら。

int tmp = fgetc(fpIn);
switch (tmp) {
  case '\r':
    if ((tmp = fgetc(fpIn)) == '\n') {
        fputs("\r\n", fpOut);
    } else {
        fputs("\r\n", fpOut);
        fputc(tmp);
    }
    break;
  case '\n':
    fputs("\r\n", fpOut);
    break;

  default:
    fputc(tmp, fpOut);
}

最後に、前回のプログラムと組み合わせた完成版がこちら。

/*
  Windows改行コードへの変換プログラム
*/
#include <stdio.h>

int sub(char *filename);

int main(int argc, char *argv[])
{
	if (argc != 2) {
		printf("コマンド引数に対象ファイルを"
                         "指定してください。\n");
		getchar();
		return 0;
	}

	sub(argv[1]);

	return 0;
}

int sub(char *filename)
{
	// "r"で開くと改行コードが自動で変換されるので、
	// バイナリモードで開く
	FILE *fp = fopen(filename, "rb");
	if (fp == NULL) {
		printf("\"%s\"が見つかりません。\n", filename);
		return 1;
	}

	FILE *fpOut = fopen("out.txt", "wb");
	if (fp == NULL)
		return 1;

	/*
	  win  \r\n
	  unix \r
	  mac  \n
	*/
	int tmp;
	while ((tmp = fgetc(fp)) != EOF) {
		switch (tmp) {
		  case '\r':
			if ((tmp = fgetc(fp)) == '\n') {
				fputs("\r\n", fpOut);
			} else {
				fputs("\r\n", fpOut);
				fputc(tmp, fpOut);
			}
			break;
		  case '\n':
			fputs("\r\n", fpOut);
			break;

		  default:
			fputc(tmp, fpOut);
		}
	}
	fclose(fpOut);
	fclose(fp);
	return 0;
}