プログラム講座 初級編13

- MacからMS-DOS(Windows)への改行コード変換 -

 初級編13です。今回は「MacからMS-DOS(Windows)への改行コード変換」を行います。ハンドルを2つ確保し片方は読み込み、もう片方は書き込むという処理を行います。




どのくらいメモリを確保すればよいか?
 今回はMac->UNIXとは異なり変換後のサイズが増えます。というのはMacの改行コードはCRのみですがMS-DOS(Windows)の場合はCR,LF、つまり2バイト必要だからです。前回の初級編12は変換元と変換先のメモリは共用(同じ)していましたが、今回そのような事をしたら変換元を破壊していってしまいます(なぜ?という人は紙に書いてみるとわかります)。
 変換元と変換先の2つのメモリを確保し、読み込みながら変換し改行コードだったらLFを追加するという処理をすれば無事に改行コードの変換を行う事ができます。

 変換後はサイズが増えるのですが、メモリは最初に確保しておいた方が楽です。しかし、どのくらいメモリを確保したらよいのでしょうか? 改行コードは頻繁に出てこないので変換元のサイズより若干多めにしておけば良いのでしょうか? 解答は「2倍」が正解です。なぜ2倍かというと全部改行コードという場合もありうるからです。プログラムする場合は「最悪の場合を考えて」おかなければなりません。そうしないと、最悪の場合システムエラー等が発生してしまいます。



ポインタを求める
 今まではハンドル操作が主でしたが、今回はハンドルからポインタを求めて処理していきます。というのは、こちらの方が処理しやすいためです。ハンドルを使った方が楽な場合とポインタを使った方が楽な場合があります。
 また改行コードが出てきた場合にカウンタを用意して1づつ加算しています。なぜカウントしているかというと変換後のサイズが最初ではわからないためです。改行コードLF分だけ増えていきますから、全部でどのくらい増えたかをカウントしておかないと書き込むときに何バイト書き込んでよいのかわからなくなってしまいます。
参考
カウンタを用意しなくても変換後のポインタアドレスから最初のポインタアドレスを引いても変換後のサイズを求める事ができます。つまりsize& = [convHandle& - pointer&]でサイズを求めることが出来ます。



終わりに
 メモリを自由に扱えるようになると作成できるプログラムの幅が広がります。是非ともマスターしましょう。



今回のプログラムリスト
' ' "改行コードを変換します" ' "CR (13) -> CRLF (10,13)" ' _crCode = 13: '"Macの改行コードはアスキーコードで13" _lfCode = 10: '"MS-DOS(Windows)の改行コードはアスキーコードで10,13" LOCAL FN convertCRtoLF CLS openfile$ = FILES$(_fOpen,"TEXT",,openRefNum%):' "ファイル選択ダイアログの表示" savefile$ = FILES$(_fSave,"ファイル名","",saveRefNum%):' "ファイル保存ダイアログの表示" LONG IF LEN(openfile$) LONG IF LEN(savefile$) DEF OPEN "TEXTEdt7" OPEN "I",#1,openfile$,,openRefNum%: ' "変換元のファイルをオープン" OPEN "O",#2,savefile$,,saveRefNum%: ' "変換先のファイルをオープン" fileSize& = LOF(1,1): ' "ファイルサイズを求める" myHandle& = FN NEWHANDLE(fileSize&): ' "ファイルサイズ分メモリを確保します!" LONG IF myHandle& = 0: ' "ハンドルサイズが0の時はメモリ不足で確保できなかった!" PRINT "■ファイルサイズが巨大なため読み込むことが出来ません" XELSE convHandle& = FN NEWHANDLE(fileSize&*2): ' "変換サイズ分メモリを確保します!" LONG IF convHandle& = 0 PRINT "■メモリ不足で変換できません" XELSE PRINT "■変換しています..." err% = FN HLOCK(myHandle&): ' "メモリが移動しないようにハンドルをロック" err% = FN HLOCK(convHandle&): ' "メモリが移動しないようにハンドルをロック" READ FILE #1,[myHandle&],fileSize&: ' "ファイルを読み込む" count& = 0: ' "変換した回数をカウントする(重要)" pointer& = [convHandle&]: ' "ポインタを求める" FOR i& = 0 TO fileSize&-1: ' "ファイルサイズ分繰り返す" code% = PEEK([myHandle&] + i&): ' "1バイト読み込む" POKE pointer&,code%: ' "変換後のメモリに1バイト書き込む" pointer& = pointer& + 1 LONG IF code% = _crCode POKE pointer&,_lfCode: ' "改行コードがCRだったらLFを追加する" pointer& = pointer& + 1 count& = count& + 1: ' "カウント数を増やす" END IF NEXT PRINT "■変換が終了しました" WRITE FILE #2,[convHandle&],fileSize&+count&:' "ファイルを書き込む" err% = FN HUNLOCK(convHandle&): ' "ハンドルロックを解除" err% = FN DISPOSHANDLE(convHandle&): ' "確保したメモリを解放する" END IF err% = FN HUNLOCK(myHandle&): ' "ハンドルロックを解除" err% = FN DISPOSHANDLE(myHandle&): ' "確保したメモリを解放する" END IF CLOSE #1,#2: ' "ファイルを閉じる" END IF END IF END FN TEXT _sysFont FN convertCRtoLF PRINT "■■ マウスボタンをクリックすると終了します ■■" WHILE FN BUTTON = _false:WEND