Объединенный Открытый Проект - Сайт для Настоящих Компьютерщиков

Объединенный Открытый Проект

Сайт для Настоящих Компьютерщиков

; Логин:
  Пароль:
Обычный
Безопасный
Запомнить пользователя



Зарегистрироваться
Забыли пароль?
 
 
 
Объединенный Открытый Проект »   Программирование »   С/C++ »   Работа с конфиг-файлами
RSS

Работа с конфиг-файлами

Вида параметр=значение


<<Назад  Вперед>>Страницы: 1 * 2
Модератор: wsx
Печать
 
wsx
Модератор раздела
Юниксойд, сетевик
wsx
Откуда: Казань
Всего сообщений: 1074
Рейтинг пользователя: 28

Репутация пользователя: 1




Дата регистрации на форуме:
14 янв. 2005
я пишу под никс на гольном си... тобишь GNU C...
Кое что уже выходит...только крЫво...
4X_Pro
Руководитель Проекта
Настоящий Компьютерщик
4X_Pro
Откуда: Москва
Всего сообщений: 2994
Рейтинг пользователя: 79





Дата регистрации на форуме:
29 сен. 2001
Ну тогда пиши свой класс. Лично я бы сделал так: в конструкторе - открывается и считывается файл, при этом происходит "нарезка" всех строк по символу = и размещение их в двух массивах: parameter и value. Соответственно, у класса есть 2 метода: getvalue и setvalue, которые получают и устанавливают значение соответствующего параметра. При желании можно сделать еще поддержку секций, но не знаю, нужно ли тебе это.
Проблема только в том, есть ли в "голом" C динамические массивы (после Perl с PHP язык без них кажется такой древностью), чтобы хранить в них указатели строки параметров.
Соответственно, в деструкторе (а лучше - в отдельной функции, вызываемой из деструктора) нужно сделать сохранение этих массивов в файл.

---
Каждый человек всегда может найти, чем он может быть полезен окружающим. Проблема только в одном: слишком многие не хотят это искать.
wsx
Модератор раздела
Юниксойд, сетевик
wsx
Откуда: Казань
Всего сообщений: 1074
Рейтинг пользователя: 28

Репутация пользователя: 1




Дата регистрации на форуме:
14 янв. 2005
ёпппрст....
Хочешь, как легче, насоветуют, как тяжелее....



Эххх...Тьфу этот си...на перле чтоли написать ??

хм...интересно, а на перле под кернел можно накатаь ? гык...



Вот зачем нужно было придумывать ТАКОЙ СЛОЖНЫЙ язык... Страуструпа и Ричарда Столмана - повесить мало!
4X_Pro
Руководитель Проекта
Настоящий Компьютерщик
4X_Pro
Откуда: Москва
Всего сообщений: 2994
Рейтинг пользователя: 79





Дата регистрации на форуме:
29 сен. 2001
А код нарезки я сделал бы таким:

int pos;
FILE* fh;
char buffer[MAXLEN]; // MAXLEN - макс. длина строки
int counter=0; // количество строк (в

fh=fopen(filename,"r");
if (fh==NULL) { обработка ошибки }
else {
fscanf(fh,"%s",buffer); // здесь еще надо подумать, как сделать, чтобы не возникало проблем с макс. длиной строки
pos=0;
whle (buffer[pos] && buffer[pos]!='=') pos++;
if (pos) {
params[counter]=malloc(pos-1); // выделение памяти под параметр
values[counter]=malloc(strlen(buffer)-pos); // выделение памяти под значение (или может быть, лучше сразу выделять с запасом?)
memcpy(params[counter],buffer,pos-1); // копирование параметра из начала строки
strcpy(values[counter],buffer+pos+1); // копирование значения из конца строки
counter++;
}
}
fclose(fh);

---
Каждый человек всегда может найти, чем он может быть полезен окружающим. Проблема только в одном: слишком многие не хотят это искать.
kolian
Новичок


Всего сообщений: 9
Рейтинг пользователя: 2





Дата регистрации на форуме:
9 авг. 2005
Я насчитал по крацней мере пять реализаций чтения из инифайла. Могу выслать исходники мыло.

---
Real programmers don't comment their code. It was hard to write, it should be hard to understand.
kolian
Новичок


Всего сообщений: 9
Рейтинг пользователя: 2





Дата регистрации на форуме:
9 авг. 2005
Вот самый простой и быстрый.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/*
*вспомагательная функция
*возвращает номер символа в строке, следующего после запятой
*или ноль, если встретит символ коментария
*
*входные параметры:
* str - строка, в которой происходит сканирование
* nom - номер элемента, начиная с которого нужно производить поиск
*
*возвращаемое значение - номер символа, ПОСЛЕ которого стоит запятая
*
*/
int get_parm_offset(char * str,int nom)
{
while((str[nom]!=',')&&(str[nom]!=';')&&(str[nom]!='\0')) nom++;
if((str[nom]==';')||(str[nom]=='\0')) return 0;
return(++nom);
}

/*
*функция conv_string() позволяет конвертировать
*переданные ей параметры из текстового вида в целочисленные.
*входные параметры:
* str - параметр-строка
*выходные параметры:
* save_buffer - буфер интеджеров ,куда следует сохранить параметр(ы)
*
*возвращаемое значение - количество элементов, помещенных в буфер - НЕ БАЙТ!!!
*/
int conv_string(char *str,int *save_buffer)
{
int nom=0; /*номер следующего символа после запятой в строке-параметре*/
int count=0;

/*save first elem. from the string*/
if(sscanf(str,"%d,",&save_buffer[count])>0) count++;

while ((nom=get_parm_offset(str,nom))!=0)
sscanf(str+nom,"%d,",&save_buffer[count++]);

return count;
}


/*
*функция read_sec_parm() позволяет прочесть
*заданный параметр секции
*из заданного конфигурационного файла
*
*входные параметры:
* filename - имя файла
* sect_num - имя секции
* parm_name - имя параметра
*выходные:
* save_buffer - буфер,куда следует сохранить параметр
* save_size - его длина
*возвращаемое значение - код ошибки
*/
int read_sec_parm(char *filename,char *sect_name,char *parm_name,char *save_buffer,size_t save_size)
{
FILE *cfg_file; /*указатель на конфигурационный файл*/
char Order[4000]; /*имя секции*/
char buf[4000]; /*временный буфер строки из файла*/
int num_char=0;

memset(Order,' ',sizeof(Order));

/*открытие конфигурационного файла на чтение*/
cfg_file=fopen(filename,"r");
if(cfg_file==NULL) { perror("Cfg.c:fopen()");return -1; }

/*построчное сканирование файла*/
while(fgets(buf,sizeof(buf),cfg_file)!=NULL)
{
int i=0;
char ch=buf;/*временная переменная, в которую заносится символ*/

/*
*замеряется отступ от начала строки
*(количество символов пробелов+табуляций)
*/
while((ch==' ')||(ch=='\t')) ch=buf[++i];

/*
*если встретился символ коментариев или новая строка, то осуществляется
*переход на следующую строку
*/
if ((ch=='#')||(ch==';')||(ch=='\n')) continue;

/*нахождение секции*/
if(sscanf(buf+i,"[%s]",Order)!=0) continue;

/*если секция не наша то дальше продолжается сканирование*/
if (strncmp(sect_name,Order,strlen(sect_name))!=0) continue;

/*сравнение названий параметров*/
if (strncmp(parm_name,buf+i,strlen(parm_name))!=0) continue;

int j=i;/*номер последнего символа в строке*/
ch=buf[j];

/*символ ' ' является допустимым*/
while((ch!='\t')&&(ch!=';')&&(ch!='#')&&(ch!='\n')) ch=buf[++j];
num_char=j-(i+strlen(parm_name)+sizeof('='));
if(num_char>=save_size) {num_char=-1;break;}
strncpy(save_buffer,&buf[i+strlen(parm_name)+sizeof('=')],num_char);
save_buffer[num_char]=0;

break;
}

/*закрытие файла*/
fclose(cfg_file);
return num_char;
}


---
Real programmers don't comment their code. It was hard to write, it should be hard to understand.
kolian
Новичок


Всего сообщений: 9
Рейтинг пользователя: 2





Дата регистрации на форуме:
9 авг. 2005
P.S. Это я написал по молодости. Сейчас я не пишу коментариев

---
Real programmers don't comment their code. It was hard to write, it should be hard to understand.
eugrus
Участник Проекта

eugrus
Всего сообщений: 195
Рейтинг пользователя: 11





Дата регистрации на форуме:
14 мар. 2005
kolian

спасибо за сорц! думаю многим пригодится

(за подробные комменты отдельное спасибо :))

---
Russian UNIX Forums
kolian
Новичок


Всего сообщений: 9
Рейтинг пользователя: 2





Дата регистрации на форуме:
9 авг. 2005
Если эта реализацию будут использовать, то я опишу ее более подробно:

Конфигурационный файл состоит из секций, параметров и комментариев. Секция состоит из параметров. Секция начинается с новой строки и содержит заключенное между символами “[“ и “]” имя секции. Параметр начинается с новой строки и следует вслед за объявлением имени секции или другого параметра и состоит из названия параметра, после которого стоит символ “=” и значения, расположенного после символа “=”. Если параметр является перечисляемым, он состоит из нескольких разделенных символом “,” элементов. Комментарий начинается либо с новой строки, либо в продолжение текущей строки и состоит из символа “#” или “;” и последующего текста комментария. Наличие комментария является необязательным. В имени секции и имени параметра не допускаются символы пробела. В значении параметра допускаются символы пробела. В имени параметра недопускаются.
Пример
[имя_секции] ; текст комментария
имя_параметра=значение параметра
имя_параметра=значение параметра 1, значение араметра 2

А это пример реального файла конфигурации:

[tcp_device1]
#~ ip=192.168.2.2
#~ ip=192.168.253.15
ip=127.0.0.1
port=10002

[tcp_device2]
#~ ip=192.168.2.2
ip=127.0.0.1
port=10000

[Errors]
Err0=0
Err1=6,20,1,2,45,1,2,56,1,2,47,1,2,42

---
Real programmers don't comment their code. It was hard to write, it should be hard to understand.
kolian
Новичок


Всего сообщений: 9
Рейтинг пользователя: 2





Дата регистрации на форуме:
9 авг. 2005
Также в тему

Configuration File Library 1.0
Configuration File Library (CFL) - портируемая библиотека, полностью написанная "с нуля" на чистом ANSI C, призванная облегчить работу с конфигурационными текстовыми файлами. Доступна для скачивания в tar.gz и rpm.
Подробности: http://freshmeat.net/projects/cfl/
Загрузить: http://download.gna.org/cfl/cfl-1.0.tar.gz

---
Real programmers don't comment their code. It was hard to write, it should be hard to understand.
wsx
Модератор раздела
Юниксойд, сетевик
wsx
Откуда: Казань
Всего сообщений: 1074
Рейтинг пользователя: 28

Репутация пользователя: 1




Дата регистрации на форуме:
14 янв. 2005
Хех...прикольно и вроде бы просто для понимания...

Осталось разобраться с безопасностью! будет ли данный метод безопасным ?! - это кстати ещё тот вопрос.
При этом, судя по быстрому изучению кода, возможно есть две проблемы:
Format String
BufferOverflow..

Хотя в код толком не вглядывался.... Надо будет посмотреть! а вобще спасибо!
kolian
Новичок


Всего сообщений: 9
Рейтинг пользователя: 2





Дата регистрации на форуме:
9 авг. 2005

wsx написал:
[q]
Хех...прикольно и вроде бы просто для понимания...

Осталось разобраться с безопасностью! будет ли данный метод безопасным ?! - это кстати ещё тот вопрос.
[/q]

Это да!!!


wsx написал:
[q]
При этом, судя по быстрому изучению кода, возможно есть две проблемы:
Format String
BufferOverflow..

Хотя в код толком не вглядывался.... Надо будет посмотреть! а вобще спасибо!
[/q]


Есть некоторые фичи:

Если в конфигурационном файле найдется строка более 4000 символов то она будет неправильно распознана.

Буду признателен за найденные ошибки


---
Real programmers don't comment their code. It was hard to write, it should be hard to understand.
wsx
Модератор раздела
Юниксойд, сетевик
wsx
Откуда: Казань
Всего сообщений: 1074
Рейтинг пользователя: 28

Репутация пользователя: 1




Дата регистрации на форуме:
14 янв. 2005
Значит так! действительно! Как только закончится выделенное [4000] место, то произойдёт Buffer Overflow!!


P.S.: А коментарии писать - полезно!
Например напишешь ты код в 15 000 строк кода, потом уедешь на отдых, приедешь и ни чего не понятно!! :)) Сколько раз так было...
4X_Pro
Руководитель Проекта
Настоящий Компьютерщик
4X_Pro
Откуда: Москва
Всего сообщений: 2994
Рейтинг пользователя: 79





Дата регистрации на форуме:
29 сен. 2001
Спорный вопрос... Тут еще надо очень тщательно сравнить: что дольше - вспоминание того, что ты хотел сделать или же сам процесс написания комментариев. Впрочем, последний сильно зависит от того, на каком языке эти самые комментарии пишутся: лично я считаю, что писать комментарии надо всегда на английском языке (в крайнем случае - по русский, но транслитом), чтобы не тратить время на переключение раскладки клавиатуры.

---
Каждый человек всегда может найти, чем он может быть полезен окружающим. Проблема только в одном: слишком многие не хотят это искать.
wsx
Модератор раздела
Юниксойд, сетевик
wsx
Откуда: Казань
Всего сообщений: 1074
Рейтинг пользователя: 28

Репутация пользователя: 1




Дата регистрации на форуме:
14 янв. 2005
Ясное дело на английском! а то та же проблема с кодировками будет!!!

А гармотно написанные коментарии - всегда помогают!

Вобщем-то это уже оффтоп!
4X_Pro
Руководитель Проекта
Настоящий Компьютерщик
4X_Pro
Откуда: Москва
Всего сообщений: 2994
Рейтинг пользователя: 79





Дата регистрации на форуме:
29 сен. 2001
Может, создать отдельную тему-опрос по этому поводу?

---
Каждый человек всегда может найти, чем он может быть полезен окружающим. Проблема только в одном: слишком многие не хотят это искать.
kolian
Новичок


Всего сообщений: 9
Рейтинг пользователя: 2





Дата регистрации на форуме:
9 авг. 2005

XXXX Pro написал:
[q]
Спорный вопрос... Тут еще надо очень тщательно сравнить: что дольше - вспоминание того, что ты хотел сделать или же сам процесс написания комментариев. Впрочем, последний сильно зависит от того, на каком языке эти самые комментарии пишутся: лично я считаю, что писать комментарии надо всегда на английском языке (в крайнем случае - по русский, но транслитом), чтобы не тратить время на переключение раскладки клавиатуры.
[/q]


Когда пишеш прогу коментарии только отвлекают.
А насчет переполнения так щас загенерю строку в пять тыщ символов и проверю на оверфлов.

---
Real programmers don't comment their code. It was hard to write, it should be hard to understand.
kolian
Новичок


Всего сообщений: 9
Рейтинг пользователя: 2





Дата регистрации на форуме:
9 авг. 2005
Мда.. действительно переполнение

Ну тут можно было поступить двумя способами: динамически ваделять память для буфера или сделать ограничение на размер строки.

Безопасность это еще тот вопрос (с)
т.к в первом случае кто нить может загенерить строку в гигабайт, тогда и ламяти для запуска других процессов не будет. Поэтому я пошел по второму пути:



--- Cfg_old.c

+++ Cfg_new.c

@@ -46,7 +46,15 @@

  return count;

}



+enum cfg_file_errors

+{

+  E_CFG_S_BUF_SIZE=-1, //длина строки из файла больше размера буфера для сохранения

+  E_CFG_I_BUF_SIZE=-2, //длина строки из файла слишком большая

+};



+/*максимальная длина строки в конфигурационном файле -1*/

+#define MAX_STRING_LEN 4096

+

/*

  *функция read_sec_parm() позволяет прочесть

  *заданный параметр секции



@@ -64,8 +72,8 @@

int read_sec_parm(char *filename,char *sect_name,char *parm_name,char *save_buffer,size_t save_size)

{

  FILE *cfg_file;    /*указатель на конфигурационный файл*/

-  char Order[4000];    /*имя секции*/

-  char buf[4000];    /*временный буфер строки из файла*/

+  char Order[MAX_STRING_LEN];    /*имя секции*/

+  char buf[MAX_STRING_LEN];    /*временный буфер строки из файла*/

  int num_char=0;

  

  memset(Order,' ',sizeof(Order));

@@ -76,7 +84,10 @@



  /*построчное сканирование файла*/

  while(fgets(buf,sizeof(buf),cfg_file)!=NULL)

-  {  

+  {

+    if(strlen(buf)==sizeof(buf)-1)

+      return E_CFG_I_BUF_SIZE;

+    

    int i=0;

    char ch=buf[i];/*временная переменная, в которую заносится символ*/

    

@@ -107,7 +118,7 @@

    /*символ ' ' является допустимым*/

    while((ch!='\t')&&(ch!=';')&&(ch!='#')&&(ch!='\n')) ch=buf[++j];

    num_char=j-(i+strlen(parm_name)+sizeof('='));

-    if(num_char>=save_size) {num_char=-1;break;}

+    if(num_char>=save_size){num_char=E_CFG_S_BUF_SIZE;break;}

    strncpy(save_buffer,&buf[i+strlen(parm_name)+sizeof('=')],num_char);

    save_buffer[num_char]=0;



---
Real programmers don't comment their code. It was hard to write, it should be hard to understand.
wsx
Модератор раздела
Юниксойд, сетевик
wsx
Откуда: Казань
Всего сообщений: 1074
Рейтинг пользователя: 28

Репутация пользователя: 1




Дата регистрации на форуме:
14 янв. 2005
Впринципе уже получше, однако действительно к вопросу безопасности стоит подходить серьёзно...
Попробую проанализировать код и погонять его на тестовой машине...Может что ещё найдётся!
Часть сообщений этой темы была выделена в тему "Вопрос по C++" (10 декабря 2007 11:02)
<<Назад  Вперед>>Страницы: 1 * 2
Модератор: wsx
Печать
Объединенный Открытый Проект »   Программирование »   С/C++ »   Работа с конфиг-файлами
RSS
Быстрый переход в раздел:


Время выполнения скрипта: 0.0627. Количество выполненных запросов: 18, время выполнения запросов 0.0404