2011-11-17 136 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似乎完成你想要的。