プログラムを実行する際、誰もが同じ設定でよいということはまれです。ユーザーの環境や好み、使用目的によって柔軟に動作を変えることができるようにしたいものです。ここでは3つの方法を紹介します。
[トップページ] / [CによるMS-DOSプログラミング>]
例えば、FOO.EXEという実行ファイルがあるとしましょう。ある設定に従って、このプログラムを動かしたいというとき、たいていはオプションを使いますね。
FOO /A /B
のように、'/'(あるいは'-')を使って、FOOの動作を決めます。UNIXでは'-'を使いますが、MS-DOSのコマンドは'/'を使っています。それはたぶん、MS-DOSでは'/'をファイル名として使えないように制限されているからだと思います。フリーソフトでは、どちらもよく使われます。どちらでもよいようにプログラミングするのが最善の方法ではないでしょうか。
C言語で、このオプションを受け取って解析するには、main()関数の宣言を、
int main( int argc, char *argv[] )
とします。
argcには、引数の数が入ります。
A>FOO /A /B
では、FOO、/A、/Bの3つなので、argcには3が入ります。FOO自体も数に入れることに注意してください。
argvのほうは、argv[ 0 ]にはFOOの先頭文字'F'のアドレスが格納されます。詳しい説明は省きますが、文字列として扱うときは、argv[ 0 ]、argv[ 1 ]のように使い、文字列中の文字を対象にするときは、argv[ 0 ][ 0 ]のように書きます(ほかにも書き方はいろいろあります)。
例:
printf( "%s\n", argv[ 0 ] ); /* FOOを表示 */
printf( "%c\n", argv[ 0 ][ 0 ] ); /* Fを表示 */
では、実際に使ってみます。
/* SAMPLE01.C */ #include <stdio.h> int main( int argc, char *argv[] ) { int i; for( i = 1; i < argc; i++ ) { if( argv[ i ][ 0 ] == '/' || argv[ i ][ 0 ] == '-' ) { printf( "オプション %c\n", argv[ i ][ 1 ] ); } else { printf( "ファイル %s\n", argv[ i ] ); } } return 0; }
A>SAMPLE01 /A -G HOGE.TXT /B BAR.EXE
このように入力して実行すると、
オプション A
オプション G
ファイル HOGE.TXT
オプション B
ファイル BAR.EXE
というように、オプションとファイルの区別ができます。'/'と'-'の両方に対応させて、ファイルとオプションの順番を問わないところがミソです。'-'から始まるファイル名は区別できませんが、とりあえずここでは制限とします。
格納される文字列は、大文字小文字を区別するので、どちらかに統一して処理をするように作ったほうがよいと思います。
このようにしてオプションやファイルを取得することができます。これをどう使うかは、あなたが決めることです :-)
環境変数は、MS-DOSのSETコマンドで登録します。AUTOEXEC.BATファイルに、
SET TEMP=A:\DOS
などと記述してあるのを見たことはありませんか? この場合、"TEMP"を環境変数と呼び、TEMPには"A:\DOS"という文字列が設定されたことになります。
これをC言語で参照するには、getenv()関数を使います。
/* SAMPLE02.C */ #include <stdio.h> #include <stdlib.h> int main( void ) { printf( "環境変数TEMPの内容は%s\n", getenv( "TEMP" )); return 0; }
環境変数が小文字で書かれていたり、イコールの前後に空白があったりすることもあるので、それを考慮するなら、もう少し複雑なことをしなければなりません。
SET TEMPやSET TMPなどは、あらかじめユーザーの環境で使っていることが多いのですが、それ以外のものは独自に決めて使うということになるでしょう。しかしユーザーは、すでにたくさんの環境変数の設定がしてあり、もうあまり使いたくないという状況が考えられます。ですから、むやみにたくさんの環境変数の設定を強要するべきではありません。メモリを消費しますし、AUTOEXEC.BATに追加するのが面倒というのがマイナスポイントです。
今回の話題とは直接関係はありませんが、パスの書き方には、
SET TEMP=A:\DOS
SET TEMP=A:\DOS\
の2通りあることに注意しなくてはなりません。正確には上が正しいと思うのですが、下の書き方をすることも考えておかないと、思わぬエラーが発生します。ただ単に最後の'\'を除去すると、"A:\"という記述がされていたときに"A:"となってしまい、chdir()関数を使うときなどに不都合が出ます。どのような処理をさせるとうまくいくでしょうか? 文字列の長さを調べるというのが、一つの方法ですね。
コマンドラインオプションでの指定は、毎回同じオプションを使うときは、いちいち書くのが面倒ですし、複数のオプションを書き並べるのも大変です。
そこで、動作を決めるための定義ファイルを別に用意し、起動時にそのファイルを読み込めば、オプションを書く必要がなくなります。通常、実行ファイルをFOO.EXEとすると、FOO.CFGやFOO.CNFというファイル名をよく使います。たぶん、CONFIGの略でしょう。これ以外には、DEFやINIという拡張子を使うこともあります。
通常、CFGファイルは、EXEファイルと同じ場所に置いておくことが前提になっています。では「EXEファイルと同じ場所」というのをどうやって知るのでしょうか。
argv[ 0 ]が指している内容を見てみましょう。FOO.EXEがA:\DOS\TOOLにあったとすると、
A:\DOS\TOOL\FOO.EXE
となっていればしめたものです。DOSのバージョンによってはこうならないこともありますが、たいていはこのようにフルパスが格納されているはずです。
CFGファイルをオープンするプログラム例です。テキストエディタでSAMPLE03.CFGというファイルを作って(内容は何でもよい)、EXEファイルと同じ場所に置けばオープンできます。CFGファイルが存在しなかったり、違う場所にあると、オープンできません。当然、実行ファイルはSAMPLE03.EXEでなければなりません。
/* SAMPLE03.C */ #include <stdio.h> #include <string.h> main( int argc, char *argv[] ) { char cfg_path[ 80 ], *ppath = cfg_path; FILE *fp; strcpy( cfg_path, argv[ 0 ] ); ppath = strrchr( cfg_path, '.' ); ppath++; strcpy( &*ppath, "CFG" ); if(( fp = fopen( cfg_path, "r" )) == NULL ) fprintf( stderr, "SAMPLE03.CFGがオープンできません\n" ); else { printf( "SAMPLE03.CFGがオープンできました\n" ); fclose( fp ); } return 0; }
まず、cfg_pathにEXEファイルのフルパスをコピーし、最後にあるピリオドへポインタを移動させ、さらにその次へ移動させます。そして、"EXE"の部分を"CFG"に書き換えてしまえば、配列cfg_pathには
A:\DOS\TOOL\SAMPLE03.CFG
のような文字列ができあがります。あとはcfg_pathを指定してオープンすれば、SAMPLE.CFGにアクセスできます。
さて、このCFGファイルの内容をどうするかという問題ですが、これもコマンドラインオプションと同じく、あなたが自由に約束事を決めればよいでしょう。
一般的には、';'や'#'の文字が来たら、改行までを読み飛ばすようにします。ここに注釈を入れたりして、何の設定をするのかを明示します。項目の書き方は、環境変数と同じように
NAME=VALUE
とすることが多いようです。
SAMPLE03.CFGの内容(一例です)。
;******************************* ; SAMPLE03 定義ファイル ;******************************* ; ;ビープ音を鳴らすかどうか(0:OFF 1:ON) ; beep=0 ; ;テンポラリファイルを作るパス ;(例:A:\FOO\BAR) ; temp_path=A:\TEMP ; ;[EOF]
CFGファイルをオープンした後は、fgets()で1行ずつ読み込み、この場合は、beepやtemp_pathの項目があるかどうかをstrstr()で比較します(その文字列が先頭にあるかどうかで調べます)。一致すれば、イコールの後ろの値を何らかの変数に代入します。以後、その変数を参照することにより、動作を変えられますね。
イコールの前後にスペースやタブが入っても認識できるようにすると、見栄えが良くなります。CFGファイルは独自に決めたフォーマットなので、ユーザーがどのように記述すればよいのか分かりやすくするため、注釈をしっかりと書く必要があります。ほかの人が使うことを想定した設計にすることは大変重要です。