2010-07-27 26 views
1

我試圖閱讀這個主題,但是當我嘗試運行我認爲是正確的事情時,它不會按照我希望的那樣做: )將命令行參數傳遞給我的程序的不同部分ANSI C

我有一個主程序,應該帶三個強制性參數,我們稱之爲t, p and s。然後我有幾個模塊,作爲其初始化的一部分,也依賴於命令行參數。這些模塊有一個命令行參數,表示它們將被使用。

當我在我的主程序中構建我的可能的命令行選項字符串時,我使它看起來像t:p:s:,我也循環所有模塊並請求其「觸發」選項字符。因此,完成的字符串可能看起來像t:p:s:iv,其中iv是兩個不同模塊的觸發器。

然後在while循環我這樣做(選項是上述字符串)

while ((opt = getopt(argc, argv, options)) != -1) { 
     switch (opt) { 
      case 't': 
       break; 
      case 's': 
       break; 
      case 'p': 
       break; 
      case 'h': 
      default: 
       ShowHelp(this, argc, argv); 
       exit(EXIT_FAILURE); 
     } 

     /* 
     * Check all available modules and see if options should be passed to it 
     */ 
     i = 0; 
     while((module = this->availablemodules[i++]) != NULL) { 
      if(opt == module->triggerArg) { 
       output = module->ParseOptions(module, argc, argv); 
       AddActiveModule(this, module); 
      } 
     } 
    } 

this->availablemodules變量是指針現有模塊的一個NULL終止的陣列。正如你所看到的,我首先檢查主程序使用的選項,然後檢查給定的選項是否是模塊的觸發選項,在這種情況下,我發送要由該模塊解析的參數。

該模塊可能會反過來有一組不同的選項。所以輸入參數可能是這個樣子的

./myprog -t foo -s bar -p 10 -i -c 2 -v -c 1 -t bar 

其中-i-v是模塊「觸發」之後那些應該在處理模塊解析功能的選項。

我該如何最好地完成這項工作?我怎樣才能最好地處理這樣一個事實,即模塊觸發選項可能與主程序所需的一個選項相同(即,t:既用作主程序中的一個選項,又用t作爲模塊「觸發器」 )?是否有能力強制執行某些命令,還是必須在解析所有選項後手動檢查該命令?

首先我使用每個模塊的選項字符串構造主程序optionstring,但是如果一個模塊不被調用會混淆系統。

我希望一切都很清楚,但如果不只是要求......我對於如何處理這個問題有點困惑,所以可能無法很好地解釋它。

更新: 我剛剛讀了一些關於getopt_long和在想,這將有可能做這樣的事情與

./myprog -t foo -s bar -p 10 --module=module1 -c 2 --module=module2 -c 1 -t bar 

,並有module1module2是什麼識別模塊激活呢?或者它會混淆解析器多次使用--module

+0

我不認爲'--module'會混淆解析器,但是您可能希望它的返回值(struct選項中的'int val')是一個不可打印的值,所以您不會限制一個可用的選項。另外,你可能希望--module設置輸入分析器的狀態,該分析器已初始化爲程序參數的狀態。或者,您可以僅使用'./myprog -t foo -s bar -p 10 --module1 -c = 2 --module1 -c = 1 --module2 -t = bar'形式的參數。你應該被警告,但getopt_long可能需要一個標誌來告訴它不要對argv進行排序,以便首先放置'-'和'--'。 – nategoose 2010-07-27 18:39:54

回答

0

我按照我在初始更新中所述的方式完成了操作。我現在通過--module=nameofModule,然後通過該模塊的所有選項。當--module選項已被識別時,我停止評估正常while循環中的選項,而是將所有以下選項放在新陣列中以傳遞給指定模塊的parseOptions函數。我一直這樣做直到我們達到新的--module選項或EOF。建議我不使用--module選項的可打印字符,因爲如果現有選項具有相同的字符,則可能會混淆解析算法,而使用字符0x07f (DEL)

struct option long_options[] = { 
     { "module", required_argument, &long_val, 0x7f }, 
     { "src", required_argument, &long_val, 's' }, 
     { "dst", required_argument, &long_val, 'd' }, 
     { 0, 0, 0, 0 }  /* terminating -0 item */ 
    }; 

我解析選項環路,則看起來有點像這樣

 // Hold pointer to a module activated by being declared in the arguments 
     module* found_module = NULL; 
     // Hold options to pass to module 
     char* module_options[256]; 
     int module_argc = 0; 

     int arg_index = 0; 

     while ((opt = getopt_long(argc, argv, "-0x7fsd", long_options, &long_opt_index)) != EOF) { 
      ++arg_index; 
      /* 
      * If we have found a module declaration store all following options until EOF or a new 
      * module is declared to be sent to the modules argument parsing function 
      */ 
      if(found_module && long_val != 0x7f) { 
       strcpy(module_options[module_argc], argv[arg_index]); 
       ++module_argc; 
      } 
      else { 

       if(found_module) { 
        output = found_module->ParseOptions(found_module, module_argc, module_options); 
        fprintf(stderr, "Adding module %s as active!\n", found_module->name); 
        AddActiveModule(this, found_module); 
        found_module = NULL; 
module_argc = 0; 
// todo: also empty the module_options array 
       } 

       switch (opt) { 
        case 0: /* this is returned for long options with option[i].flag set (not NULL). 
    the flag itself will point out the option recognized, and long_opt_index is now relevant */ 
         switch(long_val) 
         { 
          case 0x7f: 
           printf("Option --module, Argument: %s.\n", long_opt_index, optarg); 
           i = 0; 
           while((module = this->availablemodules[i++]) != NULL) { 
            if(strcmp(optarg, module->optmoduleName)) { 
             found_module = module; 
             continue; 
            } 
           } 

           break; 
           /* there's no default here */ 
         } 
         break; 
        case 'h': 
        default: 
         ShowHelp(this, argc, argv); 
         exit(EXIT_FAILURE); 
       } // switch 
      } // else 
     } // while 

    /* 
    * Have a trailing check here since EOF will terminate while loop but we might have a 
    * module left to activate 
    */ 
     if(found_module) { 
      output = found_module->ParseOptions(found_module, module_argc, module_options); 
      fprintf(stderr, "Adding module %s as active!\n", found_module->name); 
      AddActiveModule(this, found_module); 
      found_module = NULL; 
     } 

這似乎是工作完美,但我可能會錯過反正東西。正如我之前所說的,我對getopt和似乎能夠發生的自動重新排序有點困惑。當我在選項字符串的開始處收集-來防止這種情況發生時,這是否正確?

1

一種方法是參數封裝到模塊報價:

./myprog -t foo -s bar -p 10 -i="-c 2" -v="-c1 -t bar" 

,然後通過引用參數模塊。這允許您在每個模塊的一組有效參數中重複參數標識符。

或者,使用.ini文件:

[global] 
t=foo 
s=bar 
p=10 

[i] 
c=2 

[v] 
c1=true 
t=bar 

,並通過以此爲給應用程序的唯一參數。有幾個庫可以解析這種文件(我認爲它甚至是Win32 API的一部分)。

作爲.ini文件的替代方式是.xml格式,但它們解析起來更加複雜,但您可以使用架構來驗證文件。再次,有些庫可以爲你做到這一點。

+0

作爲一個澄清(這可能沒有太大的區別),目標是一個Slackware Linux發行版。用引號括起來的選項很可能會起作用,但如果用戶不需要像這樣輸入選項就好了(我猜這是一種非常不尋常的輸入參數的方式?) – inquam 2010-07-27 08:40:05

相關問題