ファイル操作関数

「ファイル操作関数」の編集履歴(バックアップ)一覧はこちら

ファイル操作関数」(2012/08/19 (日) 19:39:19) の最新版変更点

追加された行は緑色になります。

削除された行は赤色になります。

ファイル関連の機能は[[某所>>http://www5d.biglobe.ne.jp/%7Ehra/note/onechipmsx/old_contents/files/msxdoslib_080513_001.zip]] でsdcc用のライブラリが公開されているが、そのままでは動かない。 なので必要なファイルを拾ってきて、適当に修正して使う事にする。 ここで作成するsdcc用のファイル操作関数は、MSXDOSで動作するもので、 ANSI-Cのファイル関数ではなく、DOSのシステムコールを呼び出すラッパとして 動作する。ANSI-Cに近い関数ライブラリのラッパを作る事も可能だろう。 まずヘッダをサルベージして適当に修正したものを使う。 dosfile.h typedef struct { unsigned char drive_no; unsigned char name[8]; unsigned char ext[3]; unsigned int current_block; unsigned int record_size; unsigned long file_size; unsigned int date; unsigned int time; unsigned char device_id; unsigned char directory_location; unsigned int start_cluster_no; unsigned int last_access_cluster_no; unsigned int cluster_offset; unsigned char current_record; unsigned long random_record; } FCB; typedef struct { unsigned char name[8]; unsigned char ext[3]; unsigned char attribute; unsigned char undel_char; /* MSX-DOS2 */ unsigned char reserve[9]; unsigned int time; unsigned int date; unsigned int start_cluster_no; unsigned long file_size; } FCB_DIR; typedef struct { unsigned char drive_no; FCB_DIR dirinfo; } FCB_FIND; /* return code */ #define FCB_SUCCESS 0x00 /* FCB_DIR::attribute */ #define FCB_ATTR_READONLY 0x01 /* MSX-DOS2 */ #define FCB_ATTR_HIDDEN 0x02 #define FCB_ATTR_SYSTEM 0x04 /* MSX-DOS2 */ #define FCB_ATTR_VOLUME 0x08 /* MSX-DOS2 */ #define FCB_ATTR_DIR 0x10 /* MSX-DOS2 */ #define FCB_ATTR_ARCHIVE 0x20 /* MSX-DOS2 */ extern unsigned char bdos_open(FCB *); extern unsigned char bdos_close(FCB *); extern void bdos_dta(unsigned int *); extern unsigned char bdos_read(FCB *, unsigned int); extern unsigned char bdos_seqread(FCB *); extern unsigned char bdos_seqwrite(FCB *); extern unsigned char bdos_newfile(FCB *); 次にDOSファンクションコールを呼び出すC関数インターフェースを アセンブラで書く。(元のソースは動かないので) fileio.asm ; ; FCB Open ; unsigned char bdos_open(FCB *fp) ; _bdos_open:: ld hl,#2 add hl,sp ; ld e,(hl) ;FCB Pointer -> [DE] inc hl ld d,(hl) ; ld c,#0xf ;Function call 0xF(openfile) call 0x05 ; ld l,a ;return code ld h,#0 ret ; ; FCB Close ; unsigned char bdos_close(FCB *fp) ; _bdos_close:: ld hl,#2 add hl,sp ; ld e,(hl) ;FCB Pointer -> [DE] inc hl ld d,(hl) ; ld c,#0x10 ;Function call 0x10(closefile) call 0x05 ; ld l,a ;return code ld h,#0 ret ; ; SET DTA(DMA) ADDRESS ; void bdos_dta(unsigned int addr) ; _bdos_dta:: ld hl,#2 add hl,sp ; ld e,(hl) ;DTA Address -> [DE] inc hl ld d,(hl) ; ld c,#0x1a ;Function call 0x1A (DTA) call 0x05 ; ; RANDOM READ ; unsigned char bdos_read(FCB *fp,unsigned int rnumber) ; _bdos_read:: ld hl,#2 add hl,sp ; ld e,(hl) ;FCB Pointer -> [DE] inc hl ld d,(hl) inc hl ; ld c,(hl) ;Record number -> [BC] -> [HL] inc hl ld b,(hl) push bc pop hl ; ld c,#0x27 ;Function call 0x27 (Random read) call 0x05 ; ld l,a ;Return code ld h,#0 ret ; ; SEQUENTIAL READ ; unsigned char bdos_seqread(FCB *fp) ; _bdos_seqread:: ld hl,#2 add hl,sp ; ld e,(hl) ;FCB Pointer -> [DE] inc hl ld d,(hl) ; ld c,#0x14 ;Function call 0x14(sequentialread) call 0x05 ; ld l,a ;return code ld h,#0 ret ; ; SEQUENTIAL WRITE ; unsigned char bdos_seqwrite(FCB *); ; _bdos_seqwrite:: ld hl,#2 add hl,sp ; ld e,(hl) ;FCB Pointer -> [DE] inc hl ld d,(hl) ; ld c,#0x15 ;Function call 0x15(sequentialwrite) call 0x05 ; ld l,a ;return code ld h,#0 ret ; ; CREATE FILE ; unsigned char bdos_newfile(FCB *); ; _bdos_newfile:: ld hl,#2 add hl,sp ; ld e,(hl) ;FCB Pointer -> [DE] inc hl ld d,(hl) ; ld c,#0x16 ;Function call 0x16(create new) call 0x05 ; ld l,a ;return code ld h,#0 ret fileio.asmはアセンブルするとオブジェクトファイルが作成されるのでコンパイラの リンク時に指定すればよい。 >sdasz80 -o fileio.rel fileio.asm 今回作成するファイルI/O関数は、DOSファンクションコールを呼ぶもので低レベルI/O。 これらの関数はアセンブラで書かれているが、基本的にはDOSファンクションコールを 呼び出す手続きしか書かれていない。 |unsigned char bdos_open(FCB *)|ファイルを開く| |unsigned char bdos_close(FCB *)|ファイルを閉じる| |void bdos_dta(unsigned int *)|DTA(DMA)アドレスを設定| |unsigned char bdos_read(FCB *, unsigned int)|ランダムデータ読み込み| |unsigned char bdos_seqread(FCB *)|シーケンシャル読み込み| |unsigned char bdos_seqwrite(FCB *)|シーケンシャル書き込み| |unsigned char bdos_newfile(FCB *)|新規作成| -使用例 C言語のサンプル例を以下に示す。 file1.c #include "dosfile.h" void main(void){ //Create pFCB FCB *fp; //Setting Default FCB address fp=(FCB *)0x005c; //Open bdos_open(fp); //Setting buffer address bdos_dta(0x300); //Setting recordsize fp->record_size=8; fp->random_record=0; //random read buffer bdos_read(fp,1); //Close bdos_close(fp); } コンパイル方法は以下 >sdcc -mz80 -c file1.c >sdld -b _CODE=0x100 -b _DATA=0x300 -i file1.ihx file1.rel fileio.rel -l z80.lib >makebin -s 4096 file1.ihx > file1.bin >perl binout.pl file1.bin > file1.com 実行時はコマンド上でファイル名を指定する。a.txtから読み込む場合の例 A:>file1 a.txt このサンプルはDOSのファンクションコールを利用してランダムアクセスリードにより ファイルから8byteデータをバッファへ読み込む。 DOSのファイル構造体(FCB、いわゆるファイルディスクリプタ)はデフォルトで0x5Cから始まる 数バイトに確保されている。 このアドレスをFCB*としてFCB構造体へのポインタでアクセスする。 デフォルトのFCB構造体アドレスを使う場合はコマンド引数が利用出来る。 DTA(DMA)はファンクションコールで、ディスクからデータを読み書きする場合のバッファメモリのアドレスを指定する。 ファイルを開いた後に必ず指定する。 DOS(CPM)のファイル操作は128byteを単位とするが、ランダムアクセスでは指定バイト単位での リードライトが可能。 データサイズは予めレコードサイズで指定しておき、関数の引数のレコードでリードライトする。 シーケンシャルにリードする場合はbdos_seqread()を使う。このときデータは128byte単位となる。 //Setting buffer address(pass pointer to the arrary) bdos_dta(0x300); //sequential read buffer(every 128bytes) bdos_seqread(fp); //Close bdos_close(fp); デフォルトのファイルディスクリプタ(FCB)領域を使用せず、プログラム内で確保する例を 以下に示す。 文字列は左寄せで先頭から書き込み、ファイル名は8文字未満の場合はスペースで埋め空白とする。 #include "dosfile.h" #include <string.h> void main(void){ //Create FCB struct FCB fp; //Setting filename strcpy(fp.name,"ABCDEFG1"); strcpy(fp.ext,"TXT"); fp.current_block=0; fp.record_size=128; fp.current_record=0; fp.random_record=0; //Create file bdos_newfile(&fp); //Close bdos_close(&fp); } バッファーを用いてシーケンシャルアクセスで書き込む場合の例。 #include "dosfile.h" #include <string.h> void main(void){ int i; unsigned char fdata[128]; //Create FCB struct FCB fp; //Setting filename strcpy(fp.name,"BBBBBBB1"); strcpy(fp.ext,"TXT"); //Setting parameter fp.current_block=0; fp.record_size=128; fp.current_record=0; fp.random_record=0; //make file bdos_newfile(&fp); //make data for(i=0; i<128; i++){ fdata[i]=i; } //Setting DTA(data transfer address,//every 128bytes) bdos_dta((unsigned int *)&fdata); //Write data bdos_seqwrite(&fp); //additional writing,(after the second) bdos_seqwrite(&fp); //Close bdos_close(&fp); } -コマンドラインパラメータ DOSのコマンド実行時に、コマンドと共にファイル名などを指定すると自動的にファイル ディスクリプタ部分にもファイル名が格納される。 >doscmd filename.txt コマンド引数のファイル名が与えられると、0x5Cからはじまるファイルディスクリプタ(FCB) へ名前と拡張子が保存される。 0x5Cから始まるFCB領域はデフォルトでCOMMAND.COMがファイル名を自動で設定する。 プログラムはFCB構造体を指定しファンクションコールを開くだけでよい。 DOSコマンドの引数パラメータ文字列は0x80-0xFFのデータエリアに記録される。 通常この部分はCPMファンクションコールを利用するファイルアクセスの一時的なバッファ領域 として用いられるが、MSXDOSではコマンド引数の文字列が格納される。 コマンドで与えた文字列、ファイル名、オプションなどを参照する場合は、0x80から始まる文字列 を読む。 最初の1byteは文字数、最後に0xDが現われるまでの文字列がコマンドオプションである。 これらのパラメータを用いる事で、args,argvなどの引数をCから参照することができる。 プログラムはこれをargs,argvとしてそのまま利用することができる。 |0x0-0x54|CPU割り込みベクトルなどジャンプテーブル| |0x5C-0x7f|デフォルトのファイルポインタ(FCB)構造体| |0x80-0xff|バッファエリア兼コマンド文字列バッファ| |0x100-|*.COM実行ファイルロード開始アドレス| COMMAND.COMの内部コマンドであるTYPEはファイルを表示するが、このコマンドは 0x80から始まるアドレスをバッファエリアとして使う。 0x100は外部コマンドなどの実行ファイルがロードされるアドレスだが、 TYPEコマンドは内部命令なので、0x800-0x3000などのアドレス空間をバッファとして使う。 TYPEコマンドは特殊な振る舞いをする例。
ファイル関連の機能は[[某所>>http://www5d.biglobe.ne.jp/%7Ehra/note/onechipmsx/old_contents/files/msxdoslib_080513_001.zip]] でsdcc用のライブラリが公開されているが、そのままでは動かない。 なので必要なファイルを拾ってきて、適当に修正して使う事にする。 ここで作成するsdcc用のファイル操作関数は、MSXDOSで動作するもので、 ANSI-Cのファイル関数ではなく、DOSのシステムコールを呼び出すラッパとして 動作する。ANSI-Cに近い関数ライブラリのラッパを作る事も可能だろう。 まずヘッダをサルベージして適当に修正したものを使う。 dosfile.h typedef struct { unsigned char drive_no; unsigned char name[8]; unsigned char ext[3]; unsigned int current_block; unsigned int record_size; unsigned long file_size; unsigned int date; unsigned int time; unsigned char device_id; unsigned char directory_location; unsigned int start_cluster_no; unsigned int last_access_cluster_no; unsigned int cluster_offset; unsigned char current_record; unsigned long random_record; } FCB; typedef struct { unsigned char name[8]; unsigned char ext[3]; unsigned char attribute; unsigned char undel_char; /* MSX-DOS2 */ unsigned char reserve[9]; unsigned int time; unsigned int date; unsigned int start_cluster_no; unsigned long file_size; } FCB_DIR; typedef struct { unsigned char drive_no; FCB_DIR dirinfo; } FCB_FIND; /* return code */ #define FCB_SUCCESS 0x00 /* FCB_DIR::attribute */ #define FCB_ATTR_READONLY 0x01 /* MSX-DOS2 */ #define FCB_ATTR_HIDDEN 0x02 #define FCB_ATTR_SYSTEM 0x04 /* MSX-DOS2 */ #define FCB_ATTR_VOLUME 0x08 /* MSX-DOS2 */ #define FCB_ATTR_DIR 0x10 /* MSX-DOS2 */ #define FCB_ATTR_ARCHIVE 0x20 /* MSX-DOS2 */ extern unsigned char bdos_open(FCB *); extern unsigned char bdos_close(FCB *); extern void bdos_dta(unsigned int *); extern unsigned char bdos_read(FCB *, unsigned int); extern unsigned char bdos_seqread(FCB *); extern unsigned char bdos_seqwrite(FCB *); extern unsigned char bdos_newfile(FCB *); 次にDOSファンクションコールを呼び出すC関数インターフェースを アセンブラで書く。(元のソースは動かないので) fileio.asm ; ; FCB Open ; unsigned char bdos_open(FCB *fp) ; _bdos_open:: ld hl,#2 add hl,sp ; ld e,(hl) ;FCB Pointer -> [DE] inc hl ld d,(hl) ; ld c,#0xf ;Function call 0xF(openfile) call 0x05 ; ld l,a ;return code ld h,#0 ret ; ; FCB Close ; unsigned char bdos_close(FCB *fp) ; _bdos_close:: ld hl,#2 add hl,sp ; ld e,(hl) ;FCB Pointer -> [DE] inc hl ld d,(hl) ; ld c,#0x10 ;Function call 0x10(closefile) call 0x05 ; ld l,a ;return code ld h,#0 ret ; ; SET DTA(DMA) ADDRESS ; void bdos_dta(unsigned int addr) ; _bdos_dta:: ld hl,#2 add hl,sp ; ld e,(hl) ;DTA Address -> [DE] inc hl ld d,(hl) ; ld c,#0x1a ;Function call 0x1A (DTA) call 0x05 ; ; RANDOM READ ; unsigned char bdos_read(FCB *fp,unsigned int rnumber) ; _bdos_read:: ld hl,#2 add hl,sp ; ld e,(hl) ;FCB Pointer -> [DE] inc hl ld d,(hl) inc hl ; ld c,(hl) ;Record number -> [BC] -> [HL] inc hl ld b,(hl) push bc pop hl ; ld c,#0x27 ;Function call 0x27 (Random read) call 0x05 ; ld l,a ;Return code ld h,#0 ret ; ; SEQUENTIAL READ ; unsigned char bdos_seqread(FCB *fp) ; _bdos_seqread:: ld hl,#2 add hl,sp ; ld e,(hl) ;FCB Pointer -> [DE] inc hl ld d,(hl) ; ld c,#0x14 ;Function call 0x14(sequentialread) call 0x05 ; ld l,a ;return code ld h,#0 ret ; ; SEQUENTIAL WRITE ; unsigned char bdos_seqwrite(FCB *); ; _bdos_seqwrite:: ld hl,#2 add hl,sp ; ld e,(hl) ;FCB Pointer -> [DE] inc hl ld d,(hl) ; ld c,#0x15 ;Function call 0x15(sequentialwrite) call 0x05 ; ld l,a ;return code ld h,#0 ret ; ; CREATE FILE ; unsigned char bdos_newfile(FCB *); ; _bdos_newfile:: ld hl,#2 add hl,sp ; ld e,(hl) ;FCB Pointer -> [DE] inc hl ld d,(hl) ; ld c,#0x16 ;Function call 0x16(create new) call 0x05 ; ld l,a ;return code ld h,#0 ret fileio.asmはアセンブルするとオブジェクトファイルが作成されるのでコンパイラの リンク時に指定すればよい。 >sdasz80 -o fileio.rel fileio.asm 今回作成するファイルI/O関数は、DOSファンクションコールを呼ぶもので低レベルI/O。 これらの関数はアセンブラで書かれているが、基本的にはDOSファンクションコールを 呼び出す手続きしか書かれていない。 WindowsのCランタイムライブラリのファイル関数ではなく低レベルファイル関数と等しい |unsigned char bdos_open(FCB *)|ファイルを開く| |unsigned char bdos_close(FCB *)|ファイルを閉じる| |void bdos_dta(unsigned int *)|DTA(DMA)アドレスを設定| |unsigned char bdos_read(FCB *, unsigned int)|ランダムデータ読み込み| |unsigned char bdos_seqread(FCB *)|シーケンシャル読み込み| |unsigned char bdos_seqwrite(FCB *)|シーケンシャル書き込み| |unsigned char bdos_newfile(FCB *)|新規作成| -使用例 C言語のサンプル例を以下に示す。 file1.c #include "dosfile.h" void main(void){ //Create pFCB FCB *fp; //Setting Default FCB address fp=(FCB *)0x005c; //Open bdos_open(fp); //Setting buffer address bdos_dta(0x300); //Setting recordsize fp->record_size=8; fp->random_record=0; //random read buffer bdos_read(fp,1); //Close bdos_close(fp); } コンパイル方法は以下 >sdcc -mz80 -c file1.c >sdld -b _CODE=0x100 -b _DATA=0x300 -i file1.ihx file1.rel fileio.rel -l z80.lib >makebin -s 4096 file1.ihx > file1.bin >perl binout.pl file1.bin > file1.com 実行時はコマンド上でファイル名を指定する。a.txtから読み込む場合の例 A:>file1 a.txt このサンプルはDOSのファンクションコールを利用してランダムアクセスリードにより ファイルから8byteデータをバッファへ読み込む。 DOSのファイル構造体(FCB、いわゆるファイルディスクリプタ)はデフォルトで0x5Cから始まる 数バイトに確保されている。 このアドレスをFCB*としてFCB構造体へのポインタでアクセスする。 デフォルトのFCB構造体アドレスを使う場合はコマンド引数が利用出来る。 DTA(DMA)はファンクションコールで、ディスクからデータを読み書きする場合のバッファメモリのアドレスを指定する。 ファイルを開いた後に必ず指定する。 DOS(CPM)のファイル操作は128byteを単位とするが、ランダムアクセスでは指定バイト単位での リードライトが可能。 データサイズは予めレコードサイズで指定しておき、関数の引数のレコードでリードライトする。 シーケンシャルにリードする場合はbdos_seqread()を使う。このときデータは128byte単位となる。 //Setting buffer address(pass pointer to the arrary) bdos_dta(0x300); //sequential read buffer(every 128bytes) bdos_seqread(fp); //Close bdos_close(fp); デフォルトのファイルディスクリプタ(FCB)領域を使用せず、プログラム内で確保する例を 以下に示す。 文字列は左寄せで先頭から書き込み、ファイル名は8文字未満の場合はスペースで埋め空白とする。 #include "dosfile.h" #include <string.h> void main(void){ //Create FCB struct FCB fp; //Setting filename strcpy(fp.name,"ABCDEFG1"); strcpy(fp.ext,"TXT"); fp.current_block=0; fp.record_size=128; fp.current_record=0; fp.random_record=0; //Create file bdos_newfile(&fp); //Close bdos_close(&fp); } バッファーを用いてシーケンシャルアクセスで書き込む場合の例。 #include "dosfile.h" #include <string.h> void main(void){ int i; unsigned char fdata[128]; //Create FCB struct FCB fp; //Setting filename strcpy(fp.name,"BBBBBBB1"); strcpy(fp.ext,"TXT"); //Setting parameter fp.current_block=0; fp.record_size=128; fp.current_record=0; fp.random_record=0; //make file bdos_newfile(&fp); //make data for(i=0; i<128; i++){ fdata[i]=i; } //Setting DTA(data transfer address,//every 128bytes) bdos_dta((unsigned int *)&fdata); //Write data bdos_seqwrite(&fp); //additional writing,(after the second) bdos_seqwrite(&fp); //Close bdos_close(&fp); } -コマンドラインパラメータ DOSのコマンド実行時に、コマンドと共にファイル名などを指定すると自動的にファイル ディスクリプタ部分にもファイル名が格納される。 >doscmd filename.txt コマンド引数のファイル名が与えられると、0x5Cからはじまるファイルディスクリプタ(FCB) へ名前と拡張子が保存される。 0x5Cから始まるFCB領域はデフォルトでCOMMAND.COMがファイル名を自動で設定する。 プログラムはFCB構造体を指定しファンクションコールを開くだけでよい。 DOSコマンドの引数パラメータ文字列は0x80-0xFFのデータエリアに記録される。 通常この部分はCPMファンクションコールを利用するファイルアクセスの一時的なバッファ領域 として用いられるが、MSXDOSではコマンド引数の文字列が格納される。 コマンドで与えた文字列、ファイル名、オプションなどを参照する場合は、0x80から始まる文字列 を読む。 最初の1byteは文字数、最後に0xDが現われるまでの文字列がコマンドオプションである。 これらのパラメータを用いる事で、args,argvなどの引数をCから参照することができる。 プログラムはこれをargs,argvとしてそのまま利用することができる。 |0x0-0x54|CPU割り込みベクトルなどジャンプテーブル| |0x5C-0x7f|デフォルトのファイルポインタ(FCB)構造体| |0x80-0xff|バッファエリア兼コマンド文字列バッファ| |0x100-|*.COM実行ファイルロード開始アドレス| COMMAND.COMの内部コマンドであるTYPEはファイルを表示するが、このコマンドは 0x80から始まるアドレスをバッファエリアとして使う。 0x100は外部コマンドなどの実行ファイルがロードされるアドレスだが、 TYPEコマンドは内部命令なので、0x80-0x3000などのアドレス空間をバッファとして使う。 TYPEコマンドは特殊な振る舞いをする例。

表示オプション

横に並べて表示:
変化行の前後のみ表示:
ツールボックス

下から選んでください:

新しいページを作成する
ヘルプ / FAQ もご覧ください。