парсинг файла .conf в c - PullRequest
       24

парсинг файла .conf в c

2 голосов
/ 17 ноября 2011

Возможно, этот мост, вероятно, был пройден много раз и разными способами ... читая простой текстовый файл .conf и воздействуя на его записи.

В моем случае, формат файла прост .. aпоследовательность токенов и назначений, например:

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 ++.Эта роскошь на данный момент не вариант.

Ответы [ 3 ]

2 голосов
/ 17 ноября 2011

Вы можете объединить их в один массив по структурам, например,

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 голос
/ 17 ноября 2011

Я бы использовал перечисление для указания типов, чтобы вам не приходилось анализировать строку. Значения могут быть сохранены в объединении.

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

Это станет довольно громоздким, если количество ключей конфигурации станет большим. Возможно, вы захотите сохранить конфигурацию в хеш-таблице или в дереве.

Вот краткий пример , который, кажется, выполняет то, что вы хотите.

0 голосов
/ 17 ноября 2011
  1. Если мы говорим об одном и том же типе данных, используйте двойные указатели (вы получаете массив массивов)
  2. Объявите структуру, содержащую ваши указатели, затем используйте указатель на вашу структуру для работы с.

Для объявления общего указателя вы можете использовать void вместо int.Но затем каждый раз, когда вам нужно навести указатель, чтобы использовать его правильно.

...