|
Работа с конфиг-файламиВида параметр=значение
wsx
Модератор раздела
Юниксойд, сетевик
Откуда: Казань Всего сообщений: 1074 Рейтинг пользователя: 28 Репутация пользователя: 1Дата регистрации на форуме: 14 янв. 2005
|
Профиль | Сообщить модератору | ИгнорироватьNEW! Сообщение отправлено: 8 августа 2005 10:49
я пишу под никс на гольном си... тобишь GNU C...
Кое что уже выходит...только крЫво... | | |
4X_Pro
Руководитель Проекта
Настоящий Компьютерщик
Откуда: Москва Всего сообщений: 2994 Рейтинг пользователя: 79 Дата регистрации на форуме: 29 сен. 2001
|
Профиль | Сообщить модератору | ИгнорироватьNEW! Сообщение отправлено: 8 августа 2005 11:24
Ну тогда пиши свой класс. Лично я бы сделал так: в конструкторе - открывается и считывается файл, при этом происходит "нарезка" всех строк по символу = и размещение их в двух массивах: parameter и value. Соответственно, у класса есть 2 метода: getvalue и setvalue, которые получают и устанавливают значение соответствующего параметра. При желании можно сделать еще поддержку секций, но не знаю, нужно ли тебе это.
Проблема только в том, есть ли в "голом" C динамические массивы (после Perl с PHP язык без них кажется такой древностью), чтобы хранить в них указатели строки параметров.
Соответственно, в деструкторе (а лучше - в отдельной функции, вызываемой из деструктора) нужно сделать сохранение этих массивов в файл.
--- Каждый человек всегда может найти, чем он может быть полезен окружающим. Проблема только в одном: слишком многие не хотят это искать.
| | |
wsx
Модератор раздела
Юниксойд, сетевик
Откуда: Казань Всего сообщений: 1074 Рейтинг пользователя: 28 Репутация пользователя: 1Дата регистрации на форуме: 14 янв. 2005
|
Профиль | Сообщить модератору | ИгнорироватьNEW! Сообщение отправлено: 8 августа 2005 11:26
ёпппрст....
Хочешь, как легче, насоветуют, как тяжелее....
Эххх...Тьфу этот си...на перле чтоли написать ??
хм...интересно, а на перле под кернел можно накатаь ? гык...
Вот зачем нужно было придумывать ТАКОЙ СЛОЖНЫЙ язык... Страуструпа и Ричарда Столмана - повесить мало! | | |
4X_Pro
Руководитель Проекта
Настоящий Компьютерщик
Откуда: Москва Всего сообщений: 2994 Рейтинг пользователя: 79 Дата регистрации на форуме: 29 сен. 2001
|
Профиль | Сообщить модератору | ИгнорироватьNEW! Сообщение отправлено: 8 августа 2005 11:34
А код нарезки я сделал бы таким:
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
|
Профиль | Сообщить модератору | ИгнорироватьNEW! Сообщение отправлено: 9 августа 2005 18:25
Я насчитал по крацней мере пять реализаций чтения из инифайла. Могу выслать исходники мыло.
--- Real programmers don't comment their code. It was hard to write, it should be hard to understand.
| | |
kolian
Новичок
Всего сообщений: 9 Рейтинг пользователя: 2
Дата регистрации на форуме: 9 авг. 2005
|
Профиль | Сообщить модератору | ИгнорироватьNEW! Сообщение отправлено: 9 августа 2005 18:32 Сообщение отредактировано: 9 августа 2005 23:50
Вот самый простой и быстрый.
#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
|
Профиль | Сообщить модератору | ИгнорироватьNEW! Сообщение отправлено: 9 августа 2005 18:35
P.S. Это я написал по молодости. Сейчас я не пишу коментариев
--- Real programmers don't comment their code. It was hard to write, it should be hard to understand.
| | |
eugrus
Участник Проекта
Всего сообщений: 195 Рейтинг пользователя: 11 Дата регистрации на форуме: 14 мар. 2005
|
Профиль | Сообщить модератору | ИгнорироватьNEW! Сообщение отправлено: 9 августа 2005 22:37
kolian
спасибо за сорц! думаю многим пригодится
(за подробные комменты отдельное спасибо )
| | |
kolian
Новичок
Всего сообщений: 9 Рейтинг пользователя: 2
Дата регистрации на форуме: 9 авг. 2005
|
Профиль | Сообщить модератору | ИгнорироватьNEW! Сообщение отправлено: 9 августа 2005 23:20
Если эта реализацию будут использовать, то я опишу ее более подробно:
Конфигурационный файл состоит из секций, параметров и комментариев. Секция состоит из параметров. Секция начинается с новой строки и содержит заключенное между символами “[“ и “]” имя секции. Параметр начинается с новой строки и следует вслед за объявлением имени секции или другого параметра и состоит из названия параметра, после которого стоит символ “=” и значения, расположенного после символа “=”. Если параметр является перечисляемым, он состоит из нескольких разделенных символом “,” элементов. Комментарий начинается либо с новой строки, либо в продолжение текущей строки и состоит из символа “#” или “;” и последующего текста комментария. Наличие комментария является необязательным. В имени секции и имени параметра не допускаются символы пробела. В значении параметра допускаются символы пробела. В имени параметра недопускаются.
Пример
[имя_секции] ; текст комментария
имя_параметра=значение параметра
имя_параметра=значение параметра 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
|
Профиль | Сообщить модератору | ИгнорироватьNEW! Сообщение отправлено: 9 августа 2005 23:36
--- Real programmers don't comment their code. It was hard to write, it should be hard to understand.
| | |
wsx
Модератор раздела
Юниксойд, сетевик
Откуда: Казань Всего сообщений: 1074 Рейтинг пользователя: 28 Репутация пользователя: 1Дата регистрации на форуме: 14 янв. 2005
|
Профиль | Сообщить модератору | ИгнорироватьNEW! Сообщение отправлено: 10 августа 2005 9:31
Хех...прикольно и вроде бы просто для понимания...
Осталось разобраться с безопасностью! будет ли данный метод безопасным ?! - это кстати ещё тот вопрос.
При этом, судя по быстрому изучению кода, возможно есть две проблемы:
Format String
BufferOverflow..
Хотя в код толком не вглядывался.... Надо будет посмотреть! а вобще спасибо! | | |
kolian
Новичок
Всего сообщений: 9 Рейтинг пользователя: 2
Дата регистрации на форуме: 9 авг. 2005
|
Профиль | Сообщить модератору | ИгнорироватьNEW! Сообщение отправлено: 10 августа 2005 11:51 Сообщение отредактировано: 10 августа 2005 12:15
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
Модератор раздела
Юниксойд, сетевик
Откуда: Казань Всего сообщений: 1074 Рейтинг пользователя: 28 Репутация пользователя: 1Дата регистрации на форуме: 14 янв. 2005
|
Профиль | Сообщить модератору | ИгнорироватьNEW! Сообщение отправлено: 15 августа 2005 11:46
Значит так! действительно! Как только закончится выделенное [4000] место, то произойдёт Buffer Overflow!!
P.S.: А коментарии писать - полезно!
Например напишешь ты код в 15 000 строк кода, потом уедешь на отдых, приедешь и ни чего не понятно!! ) Сколько раз так было... | | |
4X_Pro
Руководитель Проекта
Настоящий Компьютерщик
Откуда: Москва Всего сообщений: 2994 Рейтинг пользователя: 79 Дата регистрации на форуме: 29 сен. 2001
|
Профиль | Сообщить модератору | ИгнорироватьNEW! Сообщение отправлено: 15 августа 2005 14:12
Спорный вопрос... Тут еще надо очень тщательно сравнить: что дольше - вспоминание того, что ты хотел сделать или же сам процесс написания комментариев. Впрочем, последний сильно зависит от того, на каком языке эти самые комментарии пишутся: лично я считаю, что писать комментарии надо всегда на английском языке (в крайнем случае - по русский, но транслитом), чтобы не тратить время на переключение раскладки клавиатуры.
--- Каждый человек всегда может найти, чем он может быть полезен окружающим. Проблема только в одном: слишком многие не хотят это искать.
| | |
wsx
Модератор раздела
Юниксойд, сетевик
Откуда: Казань Всего сообщений: 1074 Рейтинг пользователя: 28 Репутация пользователя: 1Дата регистрации на форуме: 14 янв. 2005
|
Профиль | Сообщить модератору | ИгнорироватьNEW! Сообщение отправлено: 15 августа 2005 14:14
Ясное дело на английском! а то та же проблема с кодировками будет!!!
А гармотно написанные коментарии - всегда помогают!
Вобщем-то это уже оффтоп! | | |
4X_Pro
Руководитель Проекта
Настоящий Компьютерщик
Откуда: Москва Всего сообщений: 2994 Рейтинг пользователя: 79 Дата регистрации на форуме: 29 сен. 2001
|
Профиль | Сообщить модератору | ИгнорироватьNEW! Сообщение отправлено: 15 августа 2005 14:54
Может, создать отдельную тему-опрос по этому поводу?
--- Каждый человек всегда может найти, чем он может быть полезен окружающим. Проблема только в одном: слишком многие не хотят это искать.
| | |
kolian
Новичок
Всего сообщений: 9 Рейтинг пользователя: 2
Дата регистрации на форуме: 9 авг. 2005
|
Профиль | Сообщить модератору | ИгнорироватьNEW! Сообщение отправлено: 16 августа 2005 20:41
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
|
Профиль | Сообщить модератору | ИгнорироватьNEW! Сообщение отправлено: 16 августа 2005 23:30
Мда.. действительно переполнение
Ну тут можно было поступить двумя способами: динамически ваделять память для буфера или сделать ограничение на размер строки.
Безопасность это еще тот вопрос (с)
т.к в первом случае кто нить может загенерить строку в гигабайт, тогда и ламяти для запуска других процессов не будет. Поэтому я пошел по второму пути:
--- 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
Модератор раздела
Юниксойд, сетевик
Откуда: Казань Всего сообщений: 1074 Рейтинг пользователя: 28 Репутация пользователя: 1Дата регистрации на форуме: 14 янв. 2005
|
Профиль | Сообщить модератору | ИгнорироватьNEW! Сообщение отправлено: 17 августа 2005 9:13
Впринципе уже получше, однако действительно к вопросу безопасности стоит подходить серьёзно...
Попробую проанализировать код и погонять его на тестовой машине...Может что ещё найдётся! | | |
Часть сообщений этой темы была выделена в тему "Вопрос по C++" (10 декабря 2007 11:02)
|
Время выполнения скрипта: 0.0759. Количество выполненных запросов: 18, время выполнения запросов 0.0513
|
|