/** @file tinifile.c @date 2009-04-09 @author 장길석 jwjwmx@gmail.com @brief Ver 0.0.6 Delphi에서 제공하는 TIniFile을 생성한다. @brief -# 2012-02-07 오재경 -# get_identify() 함수에서 index() 함수 리턴값 처리 -# 2010-09-14 장길석 -# 파일 없이 IniFile을 생성했을 때에도 객체가 생성되고 -# 파일로 저장할 수 있도록 수정 @todo -# 섹션을 삭제하는 함수를 추가 -# 구별자 정보를 삭제하는 함수를 추가 @bug @remark @warning - 저작권 에프에이리눅스(주) - 외부공개 금지 */ #include #include #include #include #include #include #include /// INI에서 사용하는 버퍼 크기 #define MAX_BUFFSIZE 1024 /// 섹션 문자열 최대 크기 #define MAX_SECTION 128 /// 구분자 문자열 최대 크기 #define MAX_IDENTIFY 128 /// 에러 전역 코드 int ini_error_code; // 에러코드 /// 섹션과 구분자를 위한 버퍼 char buf_text[MAX_BUFFSIZE+1]; /// 센션과 구분자에 대한 데이터를 구하기 위한 버퍼 char buf_data[MAX_BUFFSIZE+1]; static void trim( char *str) // 설명: 인수로 받은 문자열에서 앞과 뒤의 화이트 문자를 제거한다. { int sz_str; int ndx; sz_str = strlen( str); if ( 0 >= sz_str) return; // 정상적인 문자열이 아니면 바로 복귀 for ( ndx = sz_str -1; 0 <= ndx; ndx--) // 문자열 뒤의 화이트 문자를 제거, -1: NULL 위치 제거 { if ( ' ' < str[ndx]) // 한글이나 특수문자의 두번째 바이트일 경우를 대비하기 위해 MSB 비트를 확인한다. { break; } str[ndx] = '\0'; } sz_str = strlen( str); // 문자열 앞의 화이트 문자를 제거 for( ndx = 0; ndx < sz_str; ndx++) { if ( ' ' != str[ndx]) // 한글이 있을 경우를 생각해서 ' ' 문자를 직접 비교한다. break; } memcpy( str, str+ndx, strlen( str)); // 회이트 문자가 아닌 부분을 포인터의 시작 위치로 이동 } static char *get_identify( char *str, char *identify) // 설명: 인수 문자열에서 구별지 문자열을 구한다. // 참고: '='까지의 문자열을 구하며, 앞과 뒤의 화이트 문자를 제거한다. // 반환: 구별자 문자열 { char *p_data; char *p_branch; int sz_data; int pos; p_branch = index( str, '='); if ( NULL == p_branch ) return NULL; pos = p_branch -str; memcpy( identify, str, pos); identify[pos] = '\0'; sz_data = strlen( str) - pos; p_data = malloc( sz_data +1); if ( NULL != p_data) { memcpy( p_data, p_branch+1, sz_data); p_data[sz_data] = '\0'; // 복사 문자열 끝을 '\0'으로 마무리 trim( identify); trim( p_data); } return p_data; } static void get_section( char *str, char *sec) // 설명: 인수 문자열에서 섹션 문자열을 구한다. // 참고: '['와 ']' 사이의 문자를 구하며, 문자열 앞과 뒤의 화이트 문자는 제거한다. // 반환: 섹션 문자열 { int ndx_str; int ndx_sec; ndx_str = 0; while( ('\0' != str[ndx_str]) && ( ndx_str < MAX_BUFFSIZE)) { if ( '[' == str[ndx_str++]) break; } ndx_sec = 0; while( ('\0' != str[ndx_str]) && ( ndx_sec < MAX_SECTION)) { if ( ']' == str[ndx_str]) { sec[ndx_sec] = '\0'; break; } sec[ndx_sec++] = str[ndx_str++]; } trim( sec); } static int is_remark( char *str) // 설명: 문자열이 주석인지의 여부를 판단한다. // 참고: '#' 문자 또는 ';' 문자로 문장이 시작하면 주석으로 판단 // 반환: INI_TRUE=주석 { char ch_data; int ndx; ndx = 0; while( ('\0' != str[ndx]) && ( ndx < MAX_BUFFSIZE)) // 문장의 끝 또는 버퍼의 크기 만큼 확인 { ch_data = str[ndx++]; if ( '#' == ch_data) // 공백 이상의 문자 중 주석에 해당되는 '#' 문자를 만나면 주석으로 판단 { return INI_TRUE; } else if ( ';' == ch_data) // 공백 이상의 문자 중 주석에 해당되는 ';' 문자를 만나면 주석으로 판단 { return INI_TRUE; } else if ( ' ' != str[ndx]) // 공백 키워드가 아닌 공백 이상의 문자를 만나면 주석 행이 아님으로 판단 { return INI_FALSE; } } return INI_TRUE; } static int is_identify( char *str) // 설명: 문자열이 섹션 정보를 담고있는지의 여부를 반환 // 참고: '=' 문자가 있으면서 유효 // 반환: 0 = 구별자 정보가 없음, 1 = 구별자 정보가 있음 { int ndx; ndx = 0; while( ('\0' != str[ndx]) && ( ndx < MAX_BUFFSIZE)) // 문장의 끝 또는 버퍼의 크기 만큼 확인 { if ( ' ' < str[ndx++]) // 앞에 있는 공백 문자를 무시. 공백 이상의 문자가 오면 { while( ('\0' != str[ndx]) && ( ndx < MAX_BUFFSIZE)) // 공백 이상에 '=' 문자가 있는지 확인 { if ( '=' == str[ndx++]) { return 1 == 1; } } return 1 == 0; } } return 1 == 0; } static int is_section( char *str) //설명: 문자열이 섹션 정보를 담고있는지의 여부를 반환 //참고: '[' 문자가 있으면서 '[' 앞에는 빈 문자열이거나 공백 문자만 유효 // '[' 문자와 ']' 문자 사이에는 섹션에 대한 이름 문자열이 있어야 함 //반환: 0 = 섹션 정보가 없음, 1 = 섹션 정보가 있음 { char ch_data; int ndx; ndx = 0; while( ( '\0' != str[ndx]) && ( ndx < MAX_BUFFSIZE)) // 문장의 끝 또는 버퍼의 크기 만큼 확인 { ch_data = str[ndx++]; // 확인할 문자열 if ( '[' == ch_data) // 시작 [ 문자 있음 { while( ('\0' != str[ndx]) && ( ndx < MAX_BUFFSIZE)) // 문장의 끝 또는 버퍼의 크기 만큼 확인 { if ( ' ' < str[ndx++]) // [ 문자 이후에 다른 문자가 있다면 { while( ('\0' != str[ndx]) && ( ndx < MAX_BUFFSIZE)) // 문장의 끝 또는 버퍼의 크기 만큼 확인 { if ( ']' == str[ndx++]) // ] 문자가 있다면 TRUE { return 1; } } return 0; } } return 0; } else if ( ' ' != ch_data) // [ 문자 앞에 공백 문자 외에 다른 문자가 있다면 FALSE { break; } } return 0; } static void read_inifile_data( FILE *fp, inifile_t *inifile) //설명: ini 파일의 내용을 읽어들여 inifile_t 객체의 내용을 완성한다. //인수: FILE *fp : ini 파일에 대한 파일 포인터 // ifile_t *inifile : inifile_t 객체 포인터 //참고: 섹션에 따라 구별자 목록을 갖는 tstrlist를 생성하여 // 섹션 리스트의 아이템에 object로 추가한다. { char str_section [MAX_SECTION +1]; char str_identify[MAX_IDENTIFY+1]; tstrlist *lst_identify = NULL; char *p_data; while( NULL != fgets( buf_text, MAX_BUFFSIZE, fp)) { if ( INI_TRUE == is_remark( buf_text) ) // 주석 행이면 다음 행으로 ; else if ( NULL != index( buf_text, '[')) { if ( is_section( buf_text)) // 파일에서 읽어들인 문자열이 섹션 정보로 유효하다면 { lst_identify = tstrlist_create(); // 섹션에 포함된 모든 구별자 정보를 담을 수 있는 tstrlist를 생성 if ( NULL == lst_identify) { ini_error_code = INIERR_CREATE_IDENTIFY_FAIL; // 에러코드: 구별자 정보를 위한 메모리 할당 실패 return; } get_section( buf_text, str_section); tstrlist_add_object( inifile->lst_sections, str_section, lst_identify); } else lst_identify = NULL; } else if ( ( NULL != lst_identify) && is_identify( buf_text)) { p_data = get_identify( buf_text, str_identify); if ( NULL == p_data) { ini_error_code = INIERR_READ_IDENTIFY_FAIL; // 에러코드: 구별자의 문자열 정보를 메모리 할당 실패 return; } tstrlist_add_object( lst_identify, str_identify, p_data); } } inifile->is_changed = 0; } static char *read_string( inifile_t *inifile, char *str_section, char *str_identify) //설명: 섹션과 구별자의 문자열 데이터를 구한다. //인수: inifile_t *inifile : inifile_t 객체 포인터 // char *str_section : 섹션 문자열 // char *str_identify : 구별자 문자열 //반환: 섹션과 구별자의 문자열 데이터 //주의: 섹션과 구별자가 없다면 NULL을 반환 // 반환된 문자열 포인터로 메모리 소멸을 해서는 안 된다. { tstrlist *lst_section; int index; index = tstrlist_indexof( inifile->lst_sections, str_section); if ( 0 > index) return NULL; lst_section = ( tstrlist *)tstrlist_get_object( inifile->lst_sections, index); if ( NULL == lst_section) return NULL; index = tstrlist_indexof( lst_section, str_identify); if ( 0 > index) return NULL; return (char *)tstrlist_get_object( lst_section, index); } static int write_string( inifile_t *inifile, char *str_section, char *str_identify, char *data) //설명: 섹션과 구별자의 문자열 데이터를 변경 또는 추가한다. //인수: inifile_t *inifile : inifile_t 객체 포인터 // char *str_section : 섹션 문자열 // char *str_identify : 구별자 문자열 // char *data : 저장할 데이터 //반환: INI_TRUE= 변경 또는 추가 성공, INI_FALSE 변경 또는 추가 실패 //주의: 섹션과 구별자가 없다면 새로 추가한다. { tstrlist *lst_section; char *p_data; int index; inifile->is_changed = 1; // 자료 변경 이나 추가가 있음 index = tstrlist_indexof( inifile->lst_sections, str_section); if ( 0 > index) // 섹션이 없다면 추가한다. { lst_section = tstrlist_create(); // 섹션에 포함된 모든 구별자 정보를 담을 수 있는 tstrlist를 생성 if ( NULL == lst_section) { ini_error_code = INIERR_CREATE_IDENTIFY_FAIL; // 에러코드: 구별자 정보를 위한 메모리 할당 실패 return INI_FALSE; } tstrlist_add_object( inifile->lst_sections, str_section, lst_section); } else { lst_section = ( tstrlist *)tstrlist_get_object( inifile->lst_sections, index); } index = tstrlist_indexof( lst_section, str_identify); if ( 0 > index) // 구별자가 없다면 추가한다. { tstrlist_add_object( lst_section, str_identify, data); } else { p_data = (char *)tstrlist_get_object( lst_section, index); free( p_data); tstrlist_put_object( lst_section, index, data); } return INI_TRUE; } char *ini_error_string( void) /** @brief ini_error_code에 대한 에러 설명 문자열을 반환 @return 에러 코드에 대한 에러 설명 문자열 포인터 @warning 절대 반환 받은 문자열을 소멸 시켜서는 안 된다!! */ { char *error_string[] ={ "에러 없음", // INIERR_NONE "메모리 부족", // INIERR_OUT_OF_MEMORY "파일 이름 지정 오류", // INIERR_FILENAME_FAIL "자료 없음", // INIERR_NO_DATA "IniFile 없음", // INIERR_NO_FILE "IniFile을 읽을 수 없음", // INIERR_ACCESS_FAIL "섹션 리스트 생성 실패", // INIERR_CREATE_SECTION_FAIL "구별자 생성 실패", // INIERR_CREATE_IDENTIFY_FAIL "인수의 객체가 NULL" // INIERR_NULL_POINTER }; return( error_string[ini_error_code]); } int ini_print_error( char *remark) /** @brief ini_error_code에 대한 에러 설명 문자열을 화면에 출력 @param remark : 에러 설명 문자열 끝에 첨부하여 출력할 문자열 @return 에러 코드 */ { printf( "[ini error:%d]%s %s\n", ini_error_code, ini_error_string(), remark); return ini_error_code; } int ini_write_bool( inifile_t *inifile, char *str_section, char *str_identify, int value) /** @brief 섹션과 구별자가 지정하는 데이터의 값을 변경한다. @param inifile : inifile_t 객체 포인터 @param str_section : 섹션 문자열 @param str_identify : 구별자 문자열 @param value : boolean 값 @return\n INI_TRUE - 변경 또는 추가 성공\n INI_FALSE - 변경 또는 추가 실패 */ { char *data; data = malloc( 2); if ( value) sprintf( data, "1"); else sprintf( data, "0"); return write_string( inifile, str_section, str_identify, data); } int ini_write_real( inifile_t *inifile, char *str_section, char *str_identify, double value) /** @brief 섹션과 구별자가 지정하는 실수 데이터를 구한다. @param inifile : inifile_t 객체 포인터 @param str_section : 섹션 문자열 @param str_identify : 구별자 문자열 @param value : 실수 값 @return - INI_TRUE - 변경 또는 추가 성공 - INI_FALSE - 변경 또는 추가 실패 */ { char *data; data = malloc( 30); sprintf( data, "%lf", value); trim( data); return write_string( inifile, str_section, str_identify, data); } int ini_write_integer( inifile_t *inifile, char *str_section, char *str_identify, int value) /** @brief 섹션과 구별자가 지정하는 정수 데이터를 지정한다. @param inifile : inifile_t 객체 포인터 @param str_section : 섹션 문자열\n @param str_identify : 구별자 문자열\n @param value : 정수 데이터 @return - INI_TRUE - 변경 또는 추가 성공 - INI_FALSE - 변경 또는 추가 실패 */ { char *data; data = malloc( 20); sprintf( data, "%d", value); trim( data); return write_string( inifile, str_section, str_identify, data); } int ini_write_string( inifile_t *inifile, char *str_section, char *str_identify, char *value) /** @brief 섹션과 구별자의 문자열을 변경 @param inifile : inifile_t 객체 포인터 @param str_section : 섹션 문자열\n @param str_identify : 구별자 문자열\n @param value : 문자열 데이터 @return - INI_TRUE - 변경 또는 추가 성공 - INI_FALSE - 변경 또는 추가 실패 */ { char *data; data = malloc( strlen( value)+1); memcpy( data, value, strlen( value)); data[strlen(value)] = '\0'; return write_string( inifile, str_section, str_identify, data); } int ini_write_char( inifile_t *inifile, char *str_section, char *str_identify, char value) /** @brief 섹션과 구별자의 문자를 변경 @param inifile : inifile_t 객체 포인터 @param str_section : 섹션 문자열\n @param str_identify : 구별자 문자열\n @param value : 문자 @return - INI_TRUE - 변경 또는 추가 성공 - INI_FALSE - 변경 또는 추가 실패 */ { char str[16]; sprintf( str, "%c", value ); return ini_write_string( inifile, str_section, str_identify, str ); } int ini_read_bool( inifile_t *inifile, char *str_section, char *str_identify, int default_value) /** @brief 섹션과 구별자가 지정하는 Boolean 데이터를 구한다. @param inifile : inifile_t 객체 포인터 @param str_section : 섹션 문자열\n @param str_identify : 구별자 문자열\n @param default_value : 값이 없다면 대신 반환될 기본값 @warning ini 파일에 저장한 문자열이 0 이면 FALSE로 반환하며\n 이외는 무조건 TRUE로 반환한다.\n 즉, 섹션과 구별자가 가지고 있는 문자열 정보가\n '0' 인지 아닌지의 여부를 반환한다. */ { char *data; int int_data; data = read_string( inifile, str_section, str_identify); // 먼저 문자열로 데이터를 읽어 들인다. if ( NULL == data) return default_value; // 찾는 데이터가 없다면 기본값을 반환한다. else if ( 0 == strlen( data) ) return default_value; // 문자열 데이터가 없다면 기본값을 반환한다. else if ( 0 == sscanf( data, "%d", &int_data)) return default_value; // 정수로 변환된 값이 없다면 기본값을 반환 else return 0 != int_data; // 정수 값이 0이면 FALSE로 반환한다. } double ini_read_real( inifile_t *inifile, char *str_section, char *str_identify, double default_value) /** @brief 섹션과 구별자가 지정하는 실수 데이터를 구한다. @param inifile : inifile_t 객체 포인터 @param str_section : 섹션 문자열 @param str_identify : 구별자 문자열 @param default_value: 값이 없다면 대신 반환될 기본값 @return\n 섹션과 구별자에 해당하는 실수 값\n 저정한 섹션이나 구별자에 대한 실수 값이 없다면 기본값을 반환 */ { char *data; double float_data; data = read_string( inifile, str_section, str_identify); // 먼저 문자열로 데이터를 읽어 들인다. if ( NULL == data) return default_value; // 찾는 데이터가 없다면 기본값을 반환한다. else if ( 0 == strlen( data) ) return default_value; // 문자열 데이터가 없다면 기본값을 반환한다. else if ( 0 == sscanf( data, "%lf", &float_data)) return default_value; // 실수로 변환된 값이 없다면 기본값을 반환 else return float_data; // 실수 값을 반환한다. } int ini_read_integer( inifile_t *inifile, char *str_section, char *str_identify, int default_value) /** @brief 섹션과 구별자가 지정하는 정수 데이터를 구한다. @param inifile : inifile_t 객체 포인터 @param str_section : 섹션 문자열 @param str_identify : 구별자 문자열 @param default_value : 값이 없다면 대신 반환될 기본값 @return\n 섹션과 구별자에 해당하는 정수 값\n 저정한 섹션이나 구별자에 대한 정수 값이 없다면 기본값을 반환 */ { char *data; int int_data; data = read_string( inifile, str_section, str_identify); // 먼저 문자열로 데이터를 읽어 들인다. if ( NULL == data) return default_value; // 찾아진 데이터가 없다면 기본값을 반환한다. else if ( 0 == strlen( data) ) return default_value; // 문자열 데이터가 없다면 기본값을 반환한다. else if ( 0 == sscanf( data, "%d", &int_data)) return default_value; // 정수로 변환된 값이 없다면 기본값을 반환 else return int_data; // 정수값을 반환한다. } char *ini_read_string( inifile_t *inifile, char *str_section, char *str_identify, char *default_value) /** @brief 섹션과 구별자가 지정하는 문자열 데이터를 구한다. @param inifile : inifile_t 객체 포인터 @param str_section : 섹션 문자열 @param str_identify : 구별자 문자열 @param default_value : 값이 없다면 대신 반환될 기본값 @return\n 섹션과 구별자의 문자열 정보\n 저정한 섹션이나 구별자에 대한 문자열이 없다면 기본값을 반환 @warning 절대 반환 받은 문자열을 소멸 시켜서는 안 된다!! */ { char *data; data = read_string( inifile, str_section, str_identify); if ( NULL == data) return default_value; else if ( 0 == strlen( data) ) return default_value; // 문자열 데이터가 없다면 기본값을 반환한다. else return data; } char ini_read_char( inifile_t *inifile, char *str_section, char *str_identify, char default_value) /** @brief 섹션과 구별자가 지정하는 케릭터 데이타를 구한다. @param inifile : inifile_t 객체 포인터 @param str_section : 섹션 문자열 @param str_identify : 구별자 문자열 @param default_value : 값이 없다면 대신 반환될 기본값 @return\n 섹션과 구별자의 문자열 정보\n 저정한 섹션이나 구별자에 대한 문자열이 없다면 기본값을 반환 @warning 절대 반환 받은 문자열을 소멸 시켜서는 안 된다!! */ { char *cc; cc = ini_read_string( inifile, str_section, str_identify, NULL ); if ( cc ) return cc[0]; else return default_value; } tstrlist *ini_read_section( inifile_t *inifile, char *str_section) /** @brief 섹션이 가지고 있는 모든 구별자 문자열의 정보를 tstrlist 형식으로 구한다. @param inifile : inifile_t 객체 포인터 @param str_section : 섹션 문자열 @return\n 섹션이 가지고 있는 모든 구별자 문자열을 가지고 있는 tstrlist 객체\n 저정한 섹션이 없다면 NULL을 반환 @warning 절대 반환 받은 객체를 소멸 시켜서는 안 된다!! */ { tstrlist *lst_section; int index; if ( NULL == inifile) return NULL; index = tstrlist_indexof( inifile->lst_sections, str_section); if ( 0 > index) return NULL; lst_section = ( tstrlist *)tstrlist_get_object( inifile->lst_sections, index); return lst_section; } tstrlist *ini_read_sections( inifile_t *inifile) /** @brief inifile_t 객체가 가지고 있는 모든 섹션 정보를 tstrlist 형식으로 구한다. @param inifile : inifile_t 객체 포인터 @return 모든 섹션 문자열을 가지고 있는 tstrlist 객체 @warning 절대 반환 받은 객체를 소멸 시켜서는 안 된다!! */ { if ( NULL == inifile) { return NULL; } return inifile->lst_sections; } int ini_save_to_file( inifile_t *inifile, char *filename){ /** @brief inifile_t 객체 내용이 변경되어 있다면 파일로 저장한다. @param inifile : inifile_t 객체 포인터 @return INI_TRUE - 작업 중 오류 없음 */ FILE *fp_inifile; // ini 파일 객체 tstrlist *lst_sections; // inifile_t가 가지고 있는 모든 섹션 리스트 tstrlist *lst_identifies; // 섹션이 가지고 있는 구별자 리스트 char *str_section; // 섹션 문자열 char *str_identify; // 구별자 문자열 char *str_data; // 섹션과 구별자의 문자열 데이터 int ndx_sec; // 모든 섹션을 처리하기 위한 루프 인데스 int ndx_idn; // 모든 구별자를 처리하기 위한 루프 인덱스 if ( NULL == inifile) // ini 파일 개체가 없음 { ini_error_code = INIERR_NULL_POINTER; return INI_FALSE; } if ( NULL == inifile->lst_sections) { ini_error_code = INIERR_NULL_POINTER; return INI_FALSE; } fp_inifile = fopen( filename, "w"); // ini 파일을 쓰기 전용으로 열기 if ( NULL == fp_inifile) // 파일 열기 실패 { ini_error_code = INIERR_ACCESS_FAIL; // 에러코드: 파일 열기 실패 지정 return INI_FALSE; } lst_sections = ini_read_sections( inifile); // ini 객체에서 모든 섹션 리스트를 구한다. for( ndx_sec = 0; ndx_sec < tstrlist_getcount( lst_sections); ndx_sec++)// 모든 섹션에 대해서 { str_section = tstrlist_get_string( lst_sections, ndx_sec); // 섹션 문자열을 구한다. fprintf( fp_inifile, "[%s]\n", str_section); // 파일에 섹션 문자열을 쓰기 lst_identifies = ini_read_section( inifile, str_section); // 섹션의 모든 구별자 리스트를 구한다. for( ndx_idn = 0; ndx_idn < tstrlist_getcount( lst_identifies); ndx_idn++) { str_identify = tstrlist_get_string( lst_identifies, ndx_idn); str_data = ini_read_string( inifile, str_section, str_identify, ""); fprintf( fp_inifile, "%s=%s\n", str_identify, str_data); // 구별자와 데이터를 쓰기 } } fclose( fp_inifile); sync(); return INI_TRUE; } int ini_flush( inifile_t *inifile) /** @brief inifile_t 객체 내용이 변경되어 있다면 파일로 저장한다. @param inifile : inifile_t 객체 포인터 @return INI_TRUE - 작업 중 오류 없음 */ { int rst = INIERR_NONE; if ( INI_TRUE == inifile->is_changed){ // 데이터가 변경되었거나 추가되었음 inifile->is_changed = INI_FALSE; rst = ini_save_to_file( inifile, inifile->filename); } return rst; } void ini_remove_section( inifile_t *inifile, char *str_section) /** @brief 지정된 섹션을 제거합니다. @param inifile : inifile_t 객체 포인터 @param str_section : 삭제할 섹션 @warning 변경이나 추가된 자료를 위해 ini_flush()를 호출한다. */ { tstrlist *psection; char *pdata; int index; int ndx_idn; if ( NULL != inifile) { if ( NULL != inifile->lst_sections) { index = tstrlist_indexof( inifile->lst_sections, str_section); if ( 0 <= index) { psection = ( tstrlist *)tstrlist_get_object( inifile->lst_sections, index); for ( ndx_idn = 0; ndx_idn < tstrlist_getcount( psection); ndx_idn++) { pdata = ( char *)tstrlist_get_object( psection, ndx_idn); // identify에 지정된 데이터 문자열 메모리를 제거 free( pdata); } tstrlist_free( psection); tstrlist_delete( inifile->lst_sections, index); inifile->is_changed = INI_TRUE; // [KTG] section 삭제에 대해서도 파일에 반영되도록 하기 위함. } } } } void ini_free( inifile_t *inifile) /** @brief inifile_t 객체를 소멸 @param inifile : inifile_t 객체 포인터 @warning 변경이나 추가된 자료를 위해 ini_flush()를 호출한다. */ { tstrlist *psection; char *pdata; int ndx_sec; int ndx_idn; if ( NULL != inifile) { ini_flush( inifile); // 변경된 내용이 있다면 파일로 저장 if ( NULL != inifile->filename) free( inifile->filename); // 파일 이름의 메모리 소멸 if ( NULL != inifile->lst_sections) { for ( ndx_sec = 0; ndx_sec < tstrlist_getcount( inifile->lst_sections); ndx_sec++) { psection = tstrlist_get_object( inifile->lst_sections, ndx_sec); for ( ndx_idn = 0; ndx_idn < tstrlist_getcount( psection); ndx_idn++) { pdata = ( char *)tstrlist_get_object( psection, ndx_idn); // identify에 지정된 데이터 문자열 메모리를 제거 free( pdata); } tstrlist_free( psection); } tstrlist_free( inifile->lst_sections); } free( inifile); } } inifile_t *ini_create( char *filename) /** @brief filename의 내용을 섹션과 구별자로 구분하여 읽어 들인다.\n file에서 자료를 읽어 들인 후에는 데이터가 변경되어 저장이 필요하기 전까지는 \n 다시 파일을 억세스할 필요가 없다. @param filename : ini 파일의 이름 @return\n ini 파일의 모든 내용을 담은 inifile_t 객체 포인터 읽기에 실패했다면 NULL을 반환 */ { inifile_t *inifile; // ini 파일 객체 FILE *fp_inifile; // ini 파일을 읽기 위한 파일 포인터 int sz_filename; // ini 파일의 전체 이름 크기 if ( 0 != access( filename, F_OK | R_OK)) // IniFile 존재 확인 및 읽기가 가능한지 확인 { fp_inifile = fopen( filename, "w"); // 파일이 없다면 파일 생성이 가능한지를 확인한다. if ( NULL == fp_inifile) // 파일 생성에 실패했다면 에러코드 반환 { ini_error_code = INIERR_ACCESS_FAIL; // 에러코드: 파일 열기 실패 지정 return NULL; } fclose( fp_inifile); } inifile = malloc( sizeof( inifile_t)); // ini 파일 객체 생성 if ( NULL == inifile) // 객체를 위한 메모리 할당에 실패하면 { ini_error_code = INIERR_OUT_OF_MEMORY; // 에러코드 지정 return NULL; } inifile->filename = NULL; // 기본값 지정: 파일 이름 지정이 아직 안 되어 있음 inifile->lst_sections = NULL; // inifile->is_changed = INI_FALSE; // 기본값 지정: 변경된 내용이 없음 sz_filename = strlen( filename); // 파일 이름을 객체 정보에 저장한다. if ( 0 == sz_filename) { ini_free( inifile); ini_error_code = INIERR_FILENAME_FAIL; return NULL; } inifile->filename = malloc( sz_filename+1); if ( NULL == inifile->filename) // 메모리 할당에 실패했다면 에러 처리한다. { ini_free( inifile); ini_error_code = INIERR_OUT_OF_MEMORY; return NULL; } memcpy( inifile->filename, filename, sz_filename+1); inifile->lst_sections = tstrlist_create(); // 루트 섹션을 생성 if ( NULL == inifile->lst_sections) // 루트 섹션을 위한 스트링 리스트를 생성하지 못했다면 { ini_free( inifile); ini_error_code = INIERR_CREATE_SECTION_FAIL; // 에러코드: 루트 섹션 리스트 생성 return NULL; } fp_inifile = fopen( filename, "r"); // IniFile의 파일을 열기를 함 if ( NULL == fp_inifile) // 파일 열기 실패 { ini_free( inifile); ini_error_code = INIERR_ACCESS_FAIL; // 에러코드: 파일 열기 실패 지정 return NULL; } read_inifile_data( fp_inifile, inifile); // IniFile 내용을 모두 읽어 들임 fclose( fp_inifile); return inifile; }