2011-11-17 135 views
2

也許這個橋可能已經被多次穿越,並且在很多方面......讀取一個簡單的文本.conf文件並根據它的條目進行操作。解析c文件中的.conf文件

在我的情況下,該文件格式很簡單..一系列令牌和分配,如:

token_name_1 value 

用製表符作爲字段分隔符和Unix行結束的每個記錄。

.conf文件直接更改某些程序配置,它們全部存儲在單個結構中。類型的變量Integer,float,char []和* char在結構中表示。

快速而枯燥的方法包括,例如:

if (strcasecmp(token,"token_name_1")==0) 
    token_name_1=value; 

但我確定,這將是甜做契在一個不錯的緊湊循環。在C.

所以最好構建一個數組,它提供了指向我希望公開的每個結構變量的指針;另一個提供變量的名稱;和第三個描述存儲的數據類型和期望的默認值。

這些看起來是這樣的:

const char* allowed_tokens[] = 
{ 
    "loglevel", 
    "debugecho", 
    "errorSqlDisable", 
    "ClearErrorDbOnExit", 
    "\0" // terminates list 
} 

int *varpointers[] = 
{ 
    &appinfo.nLogLevel, 
    &appinfo.debugEcho, 
    &appinfo.OWFSLogLevel, 
    &appinfo.OWFSLogEchoToDisplay, 
    0 // terminates list 
}; 

char *varDatatypes_defaults[] = 
{ 
    "I|6",  // for LOG_INFO 
    "B|false", 
    "I|0", 
    "B|true", 
    "\0" // terminates list 
}; 

環路看起來是這樣的(僞):

row=0; 
while (read a line of the .conf file into cLine) 
{ 
    get the token_name and value from cLine 
    check if allowed_tokens[row]==0 and if true, exit the loop 
    // example cLine= "debugecho false" 
    find match to "debugecho" in allowed_tokens. This provides an offset into varpointers and varDatatypes. 
    get the default data type and default value tokens from varDattypes_defaults[row] 
    Do the assignment. For example, if the data type=="I": 
     *varpointers[row]=atoi(value); 

    ++row; 
} 

這種技術工作正常,但有兩個問題。

  1. 將三個陣列組合成單個陣列將是優選的。這裏有最佳做法嗎?
  2. 指針數組(varpointers [])被定義爲* int。我是這麼做的,因爲我希望它能夠持有指針。但是,如果指向的變量不是整數數據類型,則警告:將觸發不兼容指針類型的初始化。當然,char *和int *不能混合......所以如何才能做到這一點,以便使用單個指針數組?

我意識到我可以在C++中完成所有這些工作。這種奢侈品不是現在的選擇。

+0

如果您熟悉YAML(http://www.yaml.org/),那麼可以不知道,但它可能是更好的標準配置解析方式。 – Gian

回答

0
  1. 如果我們談論的是相同的數據類型,使用雙指針(你會得到一個數組的數組)
  2. 聲明一個結構牽着你的指針,然後使用的一個指針結構上下工夫。

對於聲明通用指針,可以使用void而不是int。但是,每次你必須投射指針才能正確使用它。

2

您可以通過結構將它們組合成一個數組,例如,

typedef struct { char *token; void *var; char *defaults; } the_type; 

the_type the_data[] = { { "loglevel", (void*)&appinfo.nLogLevel, "I|6" }, 
         { "debugecho", (void*)&appinfo.debugEcho, "B|false" }, 
         ... 
         }; 

通用指針類型是void *。您的代碼必須確保在實際寫入所指向的變量時使用正確的類型,例如*(int*)the_data[0] = 42;

1

我會使用枚舉來指定類型,因此您不必分析字符串。這些值可以存儲在一個聯合中。現在

typedef enum { 
    BOOLEAN, 
    INTEGER, 
} type_t; 

typedef union value { 
    bool boolean; 
    int integer; 
} value_t; 

typedef struct token { 
    char *name; 
    type_t type; 
    value_t value; 
} token_t; 

您可以定義默認值,如下所示:

token_t data[] = { 
    { "loglevel", INTEGER, { 6 } }, 
    { "debugecho", BOOLEAN, { false } }, 
    { "errorSqlDisable", INTEGER, { 0 } }, 
    { "ClearErrorDbOnExit", BOOLEAN, { true } }, 
    { 0 } 
}; 

這會得到,如果配置鍵的數量變大相當繁瑣。您可能想考慮將配置存儲在散列表或樹中。

這是一個簡短的example似乎完成你想要的。