C言語関係掲示板

過去ログ

No657 プログラム実行時の引数(オプション指定)のチェックの方法

[戻る] [ホームページ]
No.7224

プログラム実行時の引数(オプション指定)のチェックの方法
投稿者---レミ(2003/06/09 16:56:58)


プログラムの実行時の引数についての質問です。

作成しているプログラムは、
> 実行ファイル 引数1 引数2 引数3 引数4
と、最大4つ引数を持ちます。
引数1は、入力ファイル名
引数2は、-A or -a or -B or -b
引数3は、-Y or -y or -N or -n
引数4は、-I or -i or -D or -d
としています。
引数2〜3はオプションで、付けなくてもいい。
第2引数を指定し、第3を指定していない場合、
 例)実行ファイル −B[Enter]
−B −Y と指定されていることにしたい。
つまり、「−B」とした場合と、「−B −Y」としたときが同じ結果になるように作りたいと思っています。

パターンとして
-A == -A -Y
-B == -B -Y
-A -Y
-A -N
-B -Y
-B -N
-A -Y -I
-A -N -I
-B -Y -I
-B -N -I
-A -Y -D
-A -N -D
-B -Y -D
-B -N -D
の大文字小文字があります。
それで、質問なんですが、
オプション(引数)をチェックする方法で、
↓のように作ったのですが、もっといい方法はないでしょうか?
私の作ったのだと、引数のパターン(第2引数に"-C"が追加etc)が増えたりすると、
プロセスがどんどん増えていき、非常に見にくくなって行きます。
それで、もっといい方法を考えているんですが、
思いつきません。
よろしくお願いします。

OS: WindowsXP Pro
開発環境: VC++6.0(SP5)

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define OP_AY 1  // OP: -A -Y
#define OP_AN 2  // OP: -A -N
#define OP_BY 3
#define OP_BN 4

#define OP_AYI 5  // OP: -A -Y -I
#define OP_ANI 6
#define OP_BYI 7
#define OP_BNI 8  // OP: -B -N -I

#define OP_AYD 9  // OP: -A -Y -D
#define OP_AND 10
#define OP_BYD 11  // OP: -B -Y -D
#define OP_BND 12


int main( int argc, char **argv)
{
  char *fname0=NULL;
  char fbuf[1024]={0};
  FILE *fp0;
  int op=0;  // 0: オプションなし


  if( argc == 1){
    printf("入力ファイル名を入力して下さい: ");
    gets(fbuf);
    if( fbuf[0] == '\0'){  // ファイル名が入力されなかったとき
      printf("ファイル名が入力されていません.\n");
      exit(1);
    }
    fname0 = (char*)malloc( sizeof(char)*(strlen(fbuf)+1));
    strcpy( fname0, fbuf);
    if( ( fp0 = fopen( fname0, "r")) == NULL){
      printf("入力ファイル(%s)をオープンできませんでした.\n", fname0);
      exit(1);
    }
    printf("入力ファイル:  %s\n", fname0);

    printf("Option なし\n--------\n");
    
//    file_operate( fp0, op, fname0);
  }
  else{  // argc >= 2 (ファイル指定あり)

    //  入力ファイルを開く
    if( ( fp0 = fopen( argv[1], "r")) == NULL){
      printf("入力ファイル(%s)をオープンできませんでした.\n", argv[1]);
      exit(1);
    }
    printf("入力ファイル:  %s\n--------\n", argv[1]);

    if( argc > 5){
      printf("引数が多すぎます.\n");
      exit(1);
    }

    int i=3;
    while( i <= argc){
      if( strlen(argv[i-1])==2 && argv[i-1][0]=='-'){
        if(i==3){
          if( argv[i-1][1]=='A' || argv[i-1][1]=='a'){
            op = OP_AY;
          }
          else if( argv[i-1][1]=='B' || argv[i-1][1]=='b'){
            op = OP_BY;
          }
          else{
            printf("第2引数が不正.\n");
            exit(1);
          }
        }
        else if(i==4){
          if( argv[i-1][1]=='Y' || argv[i-1][1]=='y'){
            if( op == OP_AY) op = OP_AY;
            else if( op == OP_BY) op = OP_BY;
          }
          else if( argv[i-1][1]=='N' || argv[i-1][1]=='n'){
            if( op == OP_AY) op = OP_AN;
            else if( op == OP_BY) op = OP_BN;
          }
          else{
            printf("第3引数が不正.\n");
            exit(1);
          }
        }
        else if(i==5){
          if( argv[i-1][1] == 'I' || argv[i-1][1] == 'i'){
            if( op == OP_AY) op = OP_AYI;
            else if( op == OP_AN) op = OP_ANI;
            else if( op == OP_BY) op = OP_BYI;
            else if( op == OP_BN) op = OP_BNI;
          }
          else if( argv[i-1][1] == 'D' || argv[i-1][1] == 'd'){
            if( op == OP_AY) op = OP_AYD;
            else if( op == OP_AN) op = OP_AND;
            else if( op == OP_BY) op = OP_BYD;
            else if( op == OP_BN) op = OP_BND;
          }
          else{
            printf("第4引数が不正.\n");
            exit(1);
          }
        }
      }
      else{
        printf("第%d引数が不正です.\n", i-1);
        exit(1);
      }

      i++;
    }
//    file_operate( fp0, op, argv[1]);
  }
  printf("OP: %d\n", op);

  free(fname0);
  fclose(fp0);  // 入力ファイルを閉じる

  return 0;
}


No.7226

Re:プログラム実行時の引数(オプション指定)のチェックの方法
投稿者---みけ(2003/06/09 17:49:16)


option[3] のような配列を用意して、
初期状態で全て0で初期化しておく。

引数2の値は option[0] に入れる
A の時は 1 / B の時は 2
ついでに option[1] を 1 に設定

引数3の値は option[1] に入れる
Y の時は 1 / N の時は 2

引数4の値は option[2] に入れる
I の時は 1 / D の時は 2

こんな感じで管理したら引数のパターンが増えても大丈夫そうですけど、
いかがでしょうか。
それぞれ別の意味を持つ引数でしょうから、
別々に管理した方が分かりやすいと思います。
(OP_xxx のようにまとめて管理しないという意味です)


No.7227

Re:プログラム実行時の引数(オプション指定)のチェックの方法
投稿者---PSB(2003/06/09 18:11:34)


ポイントとしては
(1)ABYNDIの組み合わせを4ビットで定義する
(2)switch文のフローに注意(わざとbreakを抜いてます)
(3)toupperで大文字変換

エラーメッセージは省いてます。

#define    OP2_A    0x0001
#define    OP2_B    0x0002

#define    OP3_Y    0x0010
#define    OP3_N    0x0020

#define    OP4_D    0x0100
#define    OP4_I    0x0200
#define    OP4_NO    0x0000

int main(int argc, char* argv[])
{
    int i,j;
    int     op2;
    int     op3;
    int     op4;
    
    if(argc>5){/*    引数が多すぎる場合    */
        return 1;
    }
    
    if(argc==1){/*    ファイル名しか無い場合    */
        return 1;
    }
    
    /*    デフォルトの値    */
    op2=OP2_A;
    op3=OP3_Y;
    op4=OP4_NO;
    
    switch(argc){
    case 5:
        j=strlen(argv[4]);
        if(j<2){
            return 1;
        }
        for(i=0;i<j;i++){
            argv[4][i]=toupper(argv[4][i]);
        }
        if(argv[4][0]=='-'){
            if(argv[4][1]=='D'){
                op4=OP4_D;
            }else if(argv[4][1]=='I'){
                op4=OP4_I;
            }else{
            }
        }else{
        }
    case 4:
        j=strlen(argv[3]);
        if(j<2){
            return 1;
        }
        for(i=0;i<j;i++){
            argv[3][i]=toupper(argv[3][i]);
        }
        if(argv[3][0]=='-'){
            if(argv[3][1]=='Y'){
                op3=OP3_Y;
            }else if(argv[3][1]=='N'){
                op3=OP3_N;
            }else{
            }
        }else{
        }
    case 3:
        j=strlen(argv[2]);
        if(j<2){
            return 1;
        }
        for(i=0;i<j;i++){
            argv[2][i]=toupper(argv[2][i]);
        }
        if(argv[2][0]=='-'){
            if(argv[2][1]=='A'){
                op2=OP2_A;
            }else if(argv[2][1]=='B'){
                op2=OP2_B;
            }else{
            }
        }else{
        }
    }
    
    printf("op=%x",op2+op3+op4);
    return 0;
}




No.7230

Re:プログラム実行時の引数(オプション指定)のチェックの方法
投稿者---物見遊山(2003/06/09 18:47:03)


急ごしらえでとても汚いなーと思ったら
やっぱりバグがあったので直したんだけど
またバグるかも。
#include <stdio.h>
#include <ctype.h>
enum {
    OP_A  = 0x1,
    OP_Y  = 0x2,
    OP_I  = 0x4
};

main(int argc, char *argv[])
{
    char *cmd;
    int op = OP_Y;

    if (argc > 5 || argc < 3) {
        fprintf(stderr, "argc err\n");
        return 1;
    }

    argc--;
    for (;argc - 1; argc--) {
        if (*(cmd = argv[argc]) == '-') {
            cmd++;
            switch (toupper(*cmd)) {
            case 'A':
                op |= OP_A;
                break;
            case 'B':
                op &= ~OP_A;
                break;
            case 'Y':
                op |= OP_Y;
                break;
            case 'N':
                op &= ~OP_Y;
                break;
            case 'I':
                op |= OP_I;
                break;
            case 'D':
                op &= ~OP_I;
                break;
            default:
                fprintf(stderr, "argv err\n");
            }
        }
    }
    printf("OP: %x\n", op);

#if 0
    if (op & OP_A) {
        // Aの処理
    } else {
        // Bの処理
    }

    if (op & OP_Y) {
        // Yの処理
    } else {
        // Nの処理
    }

    if (op & OP_I) {
        // Iの処理
    } else {
        // Dの処理
    }
#endif
    return 0;
}




No.7232

Re:プログラム実行時の引数(オプション指定)のチェックの方法
投稿者---レミ(2003/06/10 00:06:05)


みけさん、PSBさん、物見遊山さん、お返事ありがとうございます。
参考にさせて頂きます。

#defineなんですが、今回のような使い方は、
引数が増えたりした時、#defineも書き換えなければならないと思うので
あまりよくないのでしょうか?

よろしくお願いします。

No.7246

Re:プログラム実行時の引数(オプション指定)のチェックの方法
投稿者---物見遊山(2003/06/10 12:26:12)


>#defineなんですが、今回のような使い方は、
>引数が増えたりした時、#defineも書き換えなければならないと思うので
>あまりよくないのでしょうか?

それはやりたいこと次第でしょう。

例えば、コマンドラインオプションの組み合わせを重視するのなら
if (op & OP_A) {
    if (op & OP_Y) {
        if (op & OP_I( {

とネストが深くなるところを
if (op & OP_AYI) {
と一行で書けたりしますから。

No.7261

Re:プログラム実行時の引数(オプション指定)のチェックの方法
投稿者---レミ(2003/06/10 14:41:20)


物見遊山さん、返信ありがとうございます。

>それはやりたいこと次第でしょう。

確かに言われる通りです。
いろいろ考えながらやってみます。
どうもありがとうございました。
また、よろしくお願いします。