在c中解析.conf文件

发布于 2024-12-16 17:33:38 字数 1838 浏览 5 评论 0原文

也许这座桥可能已经以多种方式被跨越了很多次......读取一个简单的文本 .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++ 完成这一切。此时此刻,这种奢侈不是一种选择。

Perhaps this bridge likely has been crossed many times and in many ways... reading a simple text .conf file and acting upon its entries.

In my case, the file format is simple.. a series of tokens and assignments, as in:

token_name_1    value

with a tab character as the field delimiter and a unix line-ending for each the record.

The .conf file directly alters certain program configurations, all of them stored in a single structure. Variables of types Integer, float, char[], and *char are represented in the structure.

A quick but boring approach involves, for example:

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

But I determined that it would be sweet to do the deed in a nice tight loop. In C.

So it seemed best to construct an array which provides pointers to each of the structure variables I wish to expose; another that provides the name of the variable; and a third which describes the stored data type and a desired default value.

These look like this:

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
};

The loop looks like this (pseudocode):

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;
}

This technique works fine, but there are two problems.

  1. It would be preferable to combine the three arrays into a single array. Is there a best practice here?
  2. The array of pointers (varpointers[]) is defined as *int. I did so as I want it to hold pointers. However if the variable pointed to is not an integer data type, warning: initialization from incompatible pointer type is triggered. Of course, char * and int * cannot be mixed... so how otherwise could this be done such that a single pointer array is used?

I realize I can do all this in c++. This luxury is not an option at this point.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

萌辣 2024-12-23 17:33:38

您可以通过结构体将它们组合成一个数组,例如

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;

You can combine them into one array by structs, e.g.

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" }, 
                      ... 
                      };

The generic pointer type is void *. Your code has to ensure you use the correct type when actually writing to the variable being pointed to, e.g. *(int*)the_data[0] = 42;.

甜`诱少女 2024-12-23 17:33:38

我将使用枚举来指定类型,这样您就不必解析字符串。这些值可以存储在联合中。

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 }
};

如果配置键的数量变大,这将变得非常麻烦。您可能需要考虑将配置存储在哈希表或树中。

这是一个简短的示例,似乎可以完成您想要的任务。

I would use an enumeration to specify the types so you don't have to parse a string. The values could be stored in an union.

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;

Now you can define your defaults like so:

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

This will get pretty cumbersome if the number of configuration keys gets large. You might want to think about storing the configuration in a hash table or a tree.

Here is a short example that seems to accomplish what you want.

╰◇生如夏花灿烂 2024-12-23 17:33:38
  1. 如果我们谈论相同的数据类型,请使用双指针(您将获得一个数组数组)
  2. 声明一个保存指针的结构,然后使用指向您的结构的指针进行处理。

为了声明通用指针,可以使用 void 代替 int。但每次你都必须强制转换指针才能正确使用它。

  1. If we are talking about the same data type, use double pointers (you get an array of arrays)
  2. Declare a struct holding your pointers, then use a pointer to your struct to work on.

For declaring a general pointer, you can use void instead of int. But then every time you have to cast the pointer to use it properly.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文