|
|
Работа с конфиг-файламиВида параметр=значение
wsx
Модератор раздела
Юниксойд, сетевик
 Откуда: Казань Всего сообщений: 1084 Рейтинг пользователя: 28 Репутация пользователя: 1Дата регистрации на форуме: 14 янв. 2005
|
Профиль | ИгнорироватьNEW! Сообщение отправлено: 8 августа 2005 10:49
я пишу под никс на гольном си... тобишь GNU C... Кое что уже выходит...только крЫво... | | | |
4X_Pro
Руководитель Проекта
Настоящий Компьютерщик
 Откуда: Москва Всего сообщений: 3031 Рейтинг пользователя: 75 Дата регистрации на форуме: 29 сен. 2001
|
Профиль | ИгнорироватьNEW! Сообщение отправлено: 8 августа 2005 11:24
Ну тогда пиши свой класс. Лично я бы сделал так: в конструкторе - открывается и считывается файл, при этом происходит "нарезка" всех строк по символу = и размещение их в двух массивах: parameter и value. Соответственно, у класса есть 2 метода: getvalue и setvalue, которые получают и устанавливают значение соответствующего параметра. При желании можно сделать еще поддержку секций, но не знаю, нужно ли тебе это. Проблема только в том, есть ли в "голом" C динамические массивы (после Perl с PHP язык без них кажется такой древностью), чтобы хранить в них указатели строки параметров. Соответственно, в деструкторе (а лучше - в отдельной функции, вызываемой из деструктора) нужно сделать сохранение этих массивов в файл.
--- Каждый человек всегда может найти, чем он может быть полезен окружающим. Проблема только в одном: слишком многие не хотят это искать.
| | | |
wsx
Модератор раздела
Юниксойд, сетевик
 Откуда: Казань Всего сообщений: 1084 Рейтинг пользователя: 28 Репутация пользователя: 1Дата регистрации на форуме: 14 янв. 2005
|
Профиль | ИгнорироватьNEW! Сообщение отправлено: 8 августа 2005 11:26
ёпппрст.... Хочешь, как легче, насоветуют, как тяжелее....
Эххх...Тьфу этот си...на перле чтоли написать ??
хм...интересно, а на перле под кернел можно накатаь ? гык...
Вот зачем нужно было придумывать ТАКОЙ СЛОЖНЫЙ язык... Страуструпа и Ричарда Столмана - повесить мало! | | | |
4X_Pro
Руководитель Проекта
Настоящий Компьютерщик
 Откуда: Москва Всего сообщений: 3031 Рейтинг пользователя: 75 Дата регистрации на форуме: 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
Модератор раздела
Юниксойд, сетевик
 Откуда: Казань Всего сообщений: 1084 Рейтинг пользователя: 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
Модератор раздела
Юниксойд, сетевик
 Откуда: Казань Всего сообщений: 1084 Рейтинг пользователя: 28 Репутация пользователя: 1Дата регистрации на форуме: 14 янв. 2005
|
Профиль | ИгнорироватьNEW! Сообщение отправлено: 15 августа 2005 11:46
Значит так! действительно! Как только закончится выделенное [4000] место, то произойдёт Buffer Overflow!! P.S.: А коментарии писать - полезно! Например напишешь ты код в 15 000 строк кода, потом уедешь на отдых, приедешь и ни чего не понятно!!  ) Сколько раз так было... | | | |
4X_Pro
Руководитель Проекта
Настоящий Компьютерщик
 Откуда: Москва Всего сообщений: 3031 Рейтинг пользователя: 75 Дата регистрации на форуме: 29 сен. 2001
|
Профиль | ИгнорироватьNEW! Сообщение отправлено: 15 августа 2005 14:12
Спорный вопрос... Тут еще надо очень тщательно сравнить: что дольше - вспоминание того, что ты хотел сделать или же сам процесс написания комментариев. Впрочем, последний сильно зависит от того, на каком языке эти самые комментарии пишутся: лично я считаю, что писать комментарии надо всегда на английском языке (в крайнем случае - по русский, но транслитом), чтобы не тратить время на переключение раскладки клавиатуры.
--- Каждый человек всегда может найти, чем он может быть полезен окружающим. Проблема только в одном: слишком многие не хотят это искать.
| | | |
wsx
Модератор раздела
Юниксойд, сетевик
 Откуда: Казань Всего сообщений: 1084 Рейтинг пользователя: 28 Репутация пользователя: 1Дата регистрации на форуме: 14 янв. 2005
|
Профиль | ИгнорироватьNEW! Сообщение отправлено: 15 августа 2005 14:14
Ясное дело на английском! а то та же проблема с кодировками будет!!!
А гармотно написанные коментарии - всегда помогают!
Вобщем-то это уже оффтоп! | | | |
4X_Pro
Руководитель Проекта
Настоящий Компьютерщик
 Откуда: Москва Всего сообщений: 3031 Рейтинг пользователя: 75 Дата регистрации на форуме: 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
Модератор раздела
Юниксойд, сетевик
 Откуда: Казань Всего сообщений: 1084 Рейтинг пользователя: 28 Репутация пользователя: 1Дата регистрации на форуме: 14 янв. 2005
|
Профиль | ИгнорироватьNEW! Сообщение отправлено: 17 августа 2005 9:13
Впринципе уже получше, однако действительно к вопросу безопасности стоит подходить серьёзно... Попробую проанализировать код и погонять его на тестовой машине...Может что ещё найдётся! | | | |
| Часть сообщений этой темы была выделена в тему "Вопрос по C++" (10 декабря 2007 11:02)
|
Время выполнения скрипта: 0.3538. Количество выполненных запросов: 18, время выполнения запросов 0.1107
|
|