C: чтение конфиг файла (Покажите плз пример)

Модератор: Модераторы разделов

FlySnake
Сообщения: 992
ОС: openSUSE

C: чтение конфиг файла

Сообщение FlySnake »

Всем привет
Нужно прочитать конфигурационный файл в банальном формате параметр=значение игнорируя комментарии. Первое что приходит на ум fgets+strcmp и перебирать все строки. Если погуглить, то оказывается ничего особо лучше и нет, ну ладно. Для примера смотрю исходники ncmpc и запутываюсь ещё больше.
fgets просто читает строку до конца. Далее нужно пробежаться по ней и отделить всё что левее '=' записать как параметр, всё что правее как значение при этом не забывая про '#'. Всё в цикле пока не EOF.
Но я не врублюсь как скормить fgets-у новую строку из файла. Ведь если вызывать его в цикле то он всякий раз будет читать первую строку?
Вот как в ncmpc:

Код: Выделить всё

static int
read_rc_file(char *filename)
{
    FILE *file;
    char line[MAX_LINE_LENGTH];

    if (filename == NULL)
        return -1;

    file = fopen(filename, "r");
    if (file == NULL) {
            perror(filename);
            return -1;
        }

    while (fgets(line, sizeof(line), file) != NULL) {
        char *p = g_strchug(line);

        if (*p != 0 && *p != COMMENT_TOKEN)
            parse_line(g_strchomp(p));
    }

    fclose(file);
    return 0;
}

g_strchug и g_strchomp удаляют пробелы, если я правильно понял и это функции из glib но как это работает в упор не пойму. Как fgets узнаёт какую строку нужно читать? В man 3 fgets не посылать, был там, но не нашел ответа на свой вопрос. Тупо копировать чужой код не понимая как он работает не хочу, да и лишние зависимости типо glib не нужны.
Помогите въехать плз и подскажите другой более приятный способ разбора конфиг файла.
Спасибо сказали:
Аватара пользователя
/dev/random
Администратор
Сообщения: 5413
ОС: Gentoo

Re: C: чтение конфиг файла

Сообщение /dev/random »

FlySnake писал(а):
07.06.2011 22:18
Но я не врублюсь как скормить fgets-у новую строку из файла. Ведь если вызывать его в цикле то он всякий раз будет читать первую строку?

Кто вам такое сказал???
Спасибо сказали:
FlySnake
Сообщения: 992
ОС: openSUSE

Re: C: чтение конфиг файла

Сообщение FlySnake »

/dev/random писал(а):
07.06.2011 22:41
FlySnake писал(а):
07.06.2011 22:18
Но я не врублюсь как скормить fgets-у новую строку из файла. Ведь если вызывать его в цикле то он всякий раз будет читать первую строку?

Кто вам такое сказал???

Эээ, точнее кто не сказал обратное :)
Значит на каждой итерации цикла он будет доставать новую строчку. Круто! А если после выхода из цикла где-то снова использовать этот fgets, то он прочитает следующую строку, за которой остановился в цикле, или опять первую из файла? Откуда он узнаёт между вызовами на чём остановился в прошлый раз?
Спасибо сказали:
Аватара пользователя
/dev/random
Администратор
Сообщения: 5413
ОС: Gentoo

Re: C: чтение конфиг файла

Сообщение /dev/random »

FlySnake писал(а):
07.06.2011 23:52
Значит на каждой итерации цикла он будет доставать новую строчку. Круто! А если после выхода из цикла где-то снова использовать этот fgets, то он прочитает следующую строку, за которой остановился в цикле, или опять первую из файла? Откуда он узнаёт между вызовами на чём остановился в прошлый раз?

Для каждого файлового дескриптора хранится позиция в файле, которую можно получить или изменить функцией lseek() (для дескриптора) или ftell()/fseek() (для указателя FILE*, который является обёрткой над дескриптором). Каждый раз, когда вы что-то читаете или пишете, эта позиция смещается.

Почитайте что-нибудь про работу с файлами в C.
Спасибо сказали:
Аватара пользователя
eddy
Сообщения: 3321
Статус: Красный глаз тролля
ОС: ArchLinux

Re: C: чтение конфиг файла

Сообщение eddy »

ИМХО, удобнее будет заmmap'ить файл, а потом распарсить его при помощи strchr.
RTFM
-------
KOI8-R - патриотичная кодировка Изображение
Спасибо сказали:
FlySnake
Сообщения: 992
ОС: openSUSE

Re: C: чтение конфиг файла

Сообщение FlySnake »

Как всегда выручаете, спасибо! ;)
/dev/random писал(а):
08.06.2011 00:16
Почитайте что-нибудь про работу с файлами в C

А посоветуйте чего-нибудь толковое
Спасибо сказали:
Аватара пользователя
eddy
Сообщения: 3321
Статус: Красный глаз тролля
ОС: ArchLinux

Re: C: чтение конфиг файла

Сообщение eddy »

FlySnake писал(а):
08.06.2011 00:34
А посоветуйте чего-нибудь толковое

Kernigan & Ritchie же :)
RTFM
-------
KOI8-R - патриотичная кодировка Изображение
Спасибо сказали:
FlySnake
Сообщения: 992
ОС: openSUSE

Re: C: чтение конфиг файла

Сообщение FlySnake »

eddy писал(а):
08.06.2011 00:31
ИМХО, удобнее будет заmmap'ить файл, а потом распарсить его при помощи strchr.

А быть может у Вас пример есть? А то не соображу сразу :blush:
eddy писал(а):
08.06.2011 00:46
FlySnake писал(а):
08.06.2011 00:34
А посоветуйте чего-нибудь толковое

Kernigan & Ritchie же :)

Вот там как раз про сабж (да как и вообще про всё) галопом по европам. Про сохранение позиции последнего обращения в дескрипторе сказано в коротеньком предложении, которое, видимо, проскочило мимо меня. Неуд :blush: Но всё равно K&R по стилю больше справочник чем учебник, по крайней мере мне где-то после указателей стало жутко тяжело делать упражнения, руководствуясь только информацией из книги. Поэтому сейчас больше юзаю другую книгу Mark Burgess "C Programming Tutorial".
Спасибо сказали:
Аватара пользователя
eddy
Сообщения: 3321
Статус: Красный глаз тролля
ОС: ArchLinux

Re: C: чтение конфиг файла

Сообщение eddy »

FlySnake писал(а):
08.06.2011 02:04
А быть может у Вас пример есть?

Готового примера нет. На mmap возьмите пример из манов:

Код: Выделить всё

struct stat sb;
int fs = open(filename, O_RDONLY);
if(fd < 0 ) exit(-1); // ошибка
if(stat(fd, &sb) < 0) exit(-2); // ошибка
char *buf = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
if(buf == MAP_FAILED) exit(-3); // ошибка

Ну, а дальше - обычный разбор файла, как будто он уже целиком расположен в памяти:

Код: Выделить всё

int get_param(char *buf, char *param, char **meaning){
    char *tok, *val, *par, *str;
    int stat = 0;
    str = strdup(buf);
    tok = strtok(str, "\n");
    do{
        if(strncmp(tok, "//", 2) == 0) continue; // комментарий
        if((val = strchr(tok, '=')) == NULL) continue; // отсутствие знака =
        *val++ = '\0';
        par = tok;
        if(strcasecmp(par, param)==0){
            stat = 1;
            *meaning = strdup(val);
            break;
        }
    }while((tok = strtok(NULL, "\n"))!=NULL);
    free(str);
    return stat;
}

И используем так:

Код: Выделить всё

char *val;
...
val = get_param(buf, "parameter", &val);
// далее что-то делаем с val
...
free(val); // и не забываем освобождать память
RTFM
-------
KOI8-R - патриотичная кодировка Изображение
Спасибо сказали:
Аватара пользователя
drBatty
Сообщения: 8735
Статус: GPG ID: 4DFBD1D6 дом горит, козёл не видит...
ОС: Slackware-current

Re: C: чтение конфиг файла

Сообщение drBatty »

можно использовать регулярные выражения вот вам простой пример: http://drbatty.ru/sed/ch02s04.html#bugs_i
коменнты например можно найти и удали регулярным выражением /\s*#.*/ пустые строчки потом тоже надо удалить /^\s*$/
ну а остальное должно походить под шаблон(ы) /^\s*KEY=VALUE\s*$/, при этом конечно VALUE тоже не абы какое, а например /[0-9]+/ что значит "одна или больше цифр".
http://emulek.blogspot.ru/ Windows Must Die
Учебник по sed зеркало в github

Скоро придёт
Осень
Спасибо сказали:
Аватара пользователя
eddy
Сообщения: 3321
Статус: Красный глаз тролля
ОС: ArchLinux

Re: C: чтение конфиг файла

Сообщение eddy »

drBatty писал(а):
08.06.2011 11:39
можно использовать регулярные выражения

Автор про С спрашивал, а не bash :)

// в С, конечно, тоже регулярные выражения можно использовать, но в данном случае это - забивание гвоздей микроскопом. Излишняя трата ресурсов все эти regcomp, regexec...

А метод с strtok у меня прекрасно работает в CGI для получения значений параметров, переданных POST-запросом.
RTFM
-------
KOI8-R - патриотичная кодировка Изображение
Спасибо сказали:
Аватара пользователя
Crazy
Сообщения: 862
Статус: Адепт Дзен.
ОС: Mint, Win7.

Re: C: чтение конфиг файла

Сообщение Crazy »

FlySnake писал(а):
07.06.2011 22:18
Всем привет
Нужно прочитать конфигурационный файл в банальном формате параметр=значение игнорируя комментарии. Первое что приходит на ум fgets+strcmp и перебирать все строки. Если погуглить, то оказывается ничего особо лучше и нет, ну ладно

Использовать библиотеки подобной libini

Desipere in loco
Спасибо сказали:
Аватара пользователя
eddy
Сообщения: 3321
Статус: Красный глаз тролля
ОС: ArchLinux

Re: C: чтение конфиг файла

Сообщение eddy »

Crazy писал(а):
08.06.2011 12:05
Использовать библиотеки подобной libini

Жестокая библиотечка, там даже функции работы со строками самописные :)
RTFM
-------
KOI8-R - патриотичная кодировка Изображение
Спасибо сказали:
Аватара пользователя
drBatty
Сообщения: 8735
Статус: GPG ID: 4DFBD1D6 дом горит, козёл не видит...
ОС: Slackware-current

Re: C: чтение конфиг файла

Сообщение drBatty »

eddy писал(а):
08.06.2011 12:02
в С, конечно, тоже регулярные выражения можно использовать, но в данном случае это - забивание гвоздей микроскопом. Излишняя трата ресурсов все эти regcomp, regexec...

ну-ну... Попробуйте отфильтровать комментарии в том-же BASH'е без регулярок. Для конфигов это тоже актуально, если ваше VALUE может содержать например # в кавычках. Вам придётся написать горы кода для такой простой задачки :(
eddy писал(а):
08.06.2011 12:02
А метод с strtok у меня прекрасно работает в CGI для получения значений параметров, переданных POST-запросом.

у меня тоже. Я же не спорю. Просто условия задачи недостаточно чётко оформлены. Конфиги они разные бывают. Может ТС свой скриптовый ЯП туда запихает, тогда ему и регулярок будет маловато...
http://emulek.blogspot.ru/ Windows Must Die
Учебник по sed зеркало в github

Скоро придёт
Осень
Спасибо сказали:
Аватара пользователя
/dev/random
Администратор
Сообщения: 5413
ОС: Gentoo

Re: C: чтение конфиг файла

Сообщение /dev/random »

drBatty писал(а):
08.06.2011 17:58
Может ТС свой скриптовый ЯП туда запихает, тогда ему и регулярок будет маловато...

FlySnake писал(а):
07.06.2011 22:18
конфигурационный файл в банальном формате параметр=значение игнорируя комментарии

Спасибо сказали:
FlySnake
Сообщения: 992
ОС: openSUSE

Re: C: чтение конфиг файла

Сообщение FlySnake »

drBatty писал(а):
08.06.2011 17:58
Может ТС свой скриптовый ЯП туда запихает, тогда ему и регулярок будет маловато...

ТС не настолько крут :) Это всего лишь конфиг к простенькому демону, в данный момент с 6 параметрами.
Crazy писал(а):
08.06.2011 12:05
Использовать библиотеки подобной libini

Прикольно, но громоздко для данного случая. Пока сделал на fgets.
Спасибо сказали:
Аватара пользователя
drBatty
Сообщения: 8735
Статус: GPG ID: 4DFBD1D6 дом горит, козёл не видит...
ОС: Slackware-current

Re: C: чтение конфиг файла

Сообщение drBatty »

FlySnake
в данном случае речь о данных от пользователя.
по опыту знаю: код на всяких strchr более громоздкий и вообще не обслуживаемый, чем на регулярках. даже если параметров 6, и все

Код: Выделить всё

KEY17=12345 # комментарий.

http://emulek.blogspot.ru/ Windows Must Die
Учебник по sed зеркало в github

Скоро придёт
Осень
Спасибо сказали:
Аватара пользователя
eddy
Сообщения: 3321
Статус: Красный глаз тролля
ОС: ArchLinux

Re: C: чтение конфиг файла

Сообщение eddy »

drBatty писал(а):
09.06.2011 08:16
код на всяких strchr более громоздкий и вообще не обслуживаемый, чем на регулярках

Ну, можно для проверки сделать две программки с одним и тем же функционалом, но одну на strtok+strchr, а вторую - на regcomp+regexec. И проверить, что быстрее :)
RTFM
-------
KOI8-R - патриотичная кодировка Изображение
Спасибо сказали:
Аватара пользователя
drBatty
Сообщения: 8735
Статус: GPG ID: 4DFBD1D6 дом горит, козёл не видит...
ОС: Slackware-current

Re: C: чтение конфиг файла

Сообщение drBatty »

eddy писал(а):
09.06.2011 08:44
Ну, можно для проверки сделать две программки с одним и тем же функционалом, но одну на strtok+strchr, а вторую - на regcomp+regexec. И проверить, что быстрее

зря смеётесь.
быстрее обычно получаются как раз регулярки. Потому-что:
1) они обрабатывают строчку за один проход даже для сложных условий (а вы будете просматривать строчку несколько раз).
2) регулярки компилируются, и допускают повторное использование (а ваши алгоритмы будут работать каждый раз с нуля).

Но в данном случае это не важно. Куда важнее то, что для добавления новых параметров нужно будет приложить намного меньше усилий. Например, если ТС решит ввести скажем параметр MAIL="my@example.org", то проверка валидности мыла будет для него тривиальна.

PS: http://ex-parrot.com/~pdw/Mail-RFC822-Address.html делов-то? (:
попробуйте реализовать ЭТО на strchr...
http://emulek.blogspot.ru/ Windows Must Die
Учебник по sed зеркало в github

Скоро придёт
Осень
Спасибо сказали:
Аватара пользователя
eddy
Сообщения: 3321
Статус: Красный глаз тролля
ОС: ArchLinux

Re: C: чтение конфиг файла

Сообщение eddy »

drBatty писал(а):
09.06.2011 09:00
они обрабатывают строчку за один проход даже для сложных условий

Не буду спорить, т.к. в глубины regexec'а я не вникал, и какие там алгоритмы используются, для меня совершенно темный лес...
drBatty писал(а):
09.06.2011 09:00
PS: http://ex-parrot.com/~pdw/Mail-RFC822-Address.html делов-то? (:

Это как же надо укуриться было автору такой дикой регулярки? :)

P.S. Единственным верным способом проверки правильности "мыла" является отправление по нему сообщения и ожидание ответа почтового сервера.
RTFM
-------
KOI8-R - патриотичная кодировка Изображение
Спасибо сказали:
Аватара пользователя
sash-kan
Администратор
Сообщения: 13939
Статус: oel ngati kameie
ОС: GNU

Re: C: чтение конфиг файла

Сообщение sash-kan »

eddy писал(а):
09.06.2011 10:04
Это как же надо укуриться было автору такой дикой регулярки?
никак. это выражение авто-генерируется.
подробно и популярно такая генерация (и именно на примере проверки корректности email) изложена в книге google://фридл регулярные выражения.

eddy писал(а):
09.06.2011 10:04
P.S. Единственным верным способом проверки правильности "мыла" является отправление по нему сообщения и ожидание ответа почтового сервера.
под словом «правильность» вы явно смешали два перпендикулярных понятия: «корректность адреса» и «возможность отправки писем по этому адресу».
Писать безграмотно - значит посягать на время людей, к которым мы адресуемся, а потому совершенно недопустимо в правильно организованном обществе. © Щерба Л. В., 1957
при сбоях форума см.блог
Спасибо сказали:
Аватара пользователя
drBatty
Сообщения: 8735
Статус: GPG ID: 4DFBD1D6 дом горит, козёл не видит...
ОС: Slackware-current

Re: C: чтение конфиг файла

Сообщение drBatty »

eddy писал(а):
09.06.2011 10:04
Не буду спорить, т.к. в глубины regexec'а я не вникал, и какие там алгоритмы используются, для меня совершенно темный лес...

там довольно простой алгоритм: составляется таблица, 256 слов по 32 бита (если символ == байт, как вы любите), и процессор заглатывает сразу 32 условия. Ну скажем, если нам надо найти слово "корова", то _одновременно_ проверяется
1) слово начинается на "к"
2) прошлая буква была "к", а сейчас "о"
...
6) были буквы "коров", а сейчас "а"
И если выполнился послед. пункт, то вердикт: "корова" найдена.
Естественно, это куда как быстрее, чем проверять как обычно. ИЧСХ, если условие: "либо Ф, либо ф", то алгоритм работает с той-же скоростью. Т.е. нечёткая логика не приводит к замедлению (что важно для конфигов, ибо 95% юзеров полагают, что Вася, и вАсЯ - один и тот же человек).

Конечно, всё это можно сделать и самому, вот только зачем, если в glibc это уже есть?

eddy писал(а):
09.06.2011 10:04
Это как же надо укуриться было автору такой дикой регулярки?


уже сказали... Да, это не ручками набрано ;)

eddy писал(а):
09.06.2011 10:04
P.S. Единственным верным способом проверки правильности "мыла" является отправление по нему сообщения и ожидание ответа почтового сервера.


ага. конфиг почтового сервера, этот сервер проверяет свой конфиг. Куда он почту слать будет? Сам себе? Дык он ещё даже конфиг не распарсил! Причём так с любым параметром: ну давайте ещё проверим возможность модификации файла путём его усечения до нуля (:
http://emulek.blogspot.ru/ Windows Must Die
Учебник по sed зеркало в github

Скоро придёт
Осень
Спасибо сказали:
Аватара пользователя
Crazy
Сообщения: 862
Статус: Адепт Дзен.
ОС: Mint, Win7.

Re: C: чтение конфиг файла

Сообщение Crazy »

eddy писал(а):
09.06.2011 10:04
Не буду спорить, т.к. в глубины regexec'а я не вникал, и какие там алгоритмы используются, для меня совершенно темный лес...

конечные автоматы.

Desipere in loco
Спасибо сказали: