PC-DOS 2000で遊ぶ ― 2020年03月07日 14:25
最近は、DOSで遊んでいます。DOS-BOXではなくネイティブのPC-DOSS 2000です。
仕事で最初に使ったDOSは、PC-DOS 2.11でした。360KBのディスケット1枚に収まって いたように思います。HDDナシでも使用することができました。 また、コマンドも最低限度の物しかなく、バッチファイルを沢山作って対応したものです。 現在のPC-DOS 2000は、CD-ROMか11枚のディスケットからHDDにしかインストールできな くなっています。また、非常に多くの機能を含んでいます。ものすごい進歩です。
久しぶりにDOSをインストールし動かして昔を懐かしんでもつまらないので、 過去にいじってみて断念したPSP(プログラム・セグメント接頭部)を使ったコマンドラインの 引数や環境変数の取り込みモジュールを作成してみました。
Cでかくと、コマンドラインの引数はargcと*argv[]で、環境変数はgetenv()で、それぞれ 取得することができますが、PSPを使ってこれらの機能を実現してみたかったのです。もちろん アセンブラで書きます。
PSPは、DOSからアプリケーションに制御が移った時点のDSとESにPSPが配置されている セグメントアドレスが入っています。オフセットは0000Hです。このほかに、 DOSのファンクションコール62HでBXにセグメントアドレスを得る事ができます。 今回は、ファンクションコールを利用しました。
環境変数は、PSPのオフセット2CHから1ワードに環境変数が配置されている セグメントアドレスが入っていて、オフセット0000Hから環境変数が入っています。
コマンドラインの引数は、PSPのオフセット80Hにコマンドラインの文字数(コマンドの次の ブランクからおしりの0DHまで)が、コマンドラインの文字列がオフセット81Hからに入っています。 この領域は、省略時のディスク転送領域(DTA)も兼ねているので、ファイルを操作するプログラムでは 破壊されてしまいますので、要注意です。今回はモジュール内部にコピーを取っています。
コマンドラインの引数は、デリミタ文字(スペース、タブ、カンマ)で区切られており、 クオート文字(シングルクオートかダブルクオート)で始まる場合は次のクオート文字までを ひとまとめとして取り扱います。コンマでパラメータが始まっている場合、 最初の引数はヌルストリングと見なします。また、コンマが二つ続く場合はコンマの間に ヌルストリングがあると見なします。引数はとりあえず20まで扱えるようにしてありますが、 CONSTANT.INC中のMAXARGSを変更し再ビルドすることで、増減できます。引数一つあたり1ワード 消費します。
引数の例
abc "DEF ghijk" ---> [abc]、[DEF ghijk]の二つ ("["、"]"は目印の文字) , 123<TAB>567 ------> []、[123]、[567] (<TAB>はタブ文字) ABCDEF , , XYZ ----> [ABCDEF]、[]、[XYZ] XYZ "abc'def" ------> [XYZ]、[abc'def] abc 'def'ghi -------> [abc]、[def]、[ghi] xyz"abc<TAB>def ----> [xyz]、[abc<TAB>def]
作ってみたところ、マクロや定数を含めて約500行のプログラムができあがりました。 完成した物は envaergs.zipです。
作り込んだのは、@getArgc,@getArgv,@getEnvの三つです。
@getArgcは、引数の個数を返します。
@getArgvは、指定された位置の引数を返します。
@getEnvは、指定された環境変数名の値を返します。
サンプルを2本作りました。
コマンドラインの引数を一行に一つづつ表示する"args.asm"。これは引数 を取得するサンプルです。引数の書き出しは目印に"["と"]"で囲んでいます。
もう一つのサンプルは、"printenv.asm"です。これは、引数で受け取った環境変数名を 探しだしその値を書き出します。変数名とその値は目印"["、"]"で囲んで表示します。
printenv.asmは以下の通りです。ちなみに関数の呼び出しは全てマクロでラップしてあります。 いかがでしょうか。
PAGE ,132 TITLE PRINTENV.ASM -- Test Stub %OUT PRINTENV.ASM INCLUDE CONSTANT.INC INCLUDE ENVARGS.INC myStack SEGMENT PARA STACK DB 128 DUP("@") myStack ENDS myData SEGMENT PARA PUBLIC 'DATA' Msg0 DB "[", EOS Msg1 DB "]=[", EOS Msg2 DB "]", CRCHAR, LFCHAR, EOS Argc DB 0 ArgIndex DB 0 EnvName DB 128 DUP('*'), EOS EnvValue DB 128 DUP('@'), EOS myData ENDS myTest SEGMENT PARA ASSUME CS:myTest, DS:myData, ES:myData, SS:myStack main PROC MOV AX, myData MOV DS, AX MOV Argc, 0 MOV ArgIndex, 1 @getArgc Argc main2: MOV AL, ArgIndex CMP AL, Argc JG main1 MOV SI, OFFSET Msg0 CALL putstr @getArgv ArgIndex, EnvName MOV SI, OFFSET EnvName CALL toupper CALL putstr MOV SI, OFFSET Msg1 CALL putstr @getEnv EnvName, EnvValue MOV SI, OFFSET EnvValue CALL putstr MOV SI, OFFSET Msg2 CALL putstr INC ArgIndex JMP main2 main1: MOV AL, 0 MOV AH, 4CH INT 21H main ENDP toupper PROC MOV DI, SI toupper2: MOV AL, BYTE PTR [DI] CMP AL, EOS JE toupper1 CMP AL, 'a' JL toupper3 CMP AL, 'z' JG toupper3 SUB AL, 'a'-'A' MOV [DI], AL toupper3: INC DI JMP toupper2 toupper1: toupper ENDP putstr PROC putstr2: MOV AL, BYTE PTR DS:[SI] CMP AL, EOS JE putstr1 MOV BX, STDOUT MOV CX, 1 MOV DX, SI MOV AH, 40H INT 21H INC SI JMP putstr2 putstr1: RET putstr ENDP myTest ENDS END main
最近のコメント