strparsing.c 13.2 KB
/**
    @file   strparsing.c
    @date   2009-06-01
    @author 장길석 jwjwmx@gmail.com
    @brief  Ver 0.0.4
            문자열을 분석하여 tstrlist로 생성한다.
    @todo
    @bug
    @remark
    @warning
        - 저작권    에프에이리눅스(주)
        - 외부공개 금지
    @section ModifyInfo 수정 정보
        - 2009-07-06
            -# Doxygen을 위한 주석 수정
        - 2009-06-01
            -# 기본 기능을 추가
*/
//------------------------------------------------------------------------------
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include <tlist.h>
#include <tstrlist.h>
#include <strparsing.h>

#define MAX_BUFFSIZE        1024
#define MAX_IDENTIFY        128

int     strp_error_code;                                                        // 에러코드

static char buff_parse[1024];
static char buff_identify[1024];

static char *read_string( tstrlist *strplist, char *str_identify)
//설명: 구별자의 문자열 데이터를 구한다.
//인수: tstrlist *strplist  : tstrlist 객체 포인터
//      char *str_identify  : 구별자 문자열
//반환: 섹션과 구별자의 문자열 데이터
//주의: 섹션과 구별자가 없다면 NULL을 반환
//      반환된 문자열 포인터로 메모리 소멸을 해서는 안 된다.
{
    int     index;
    
    index   = tstrlist_indexof( strplist, str_identify);
    if ( 0 > index) return NULL;

    return (char *)tstrlist_get_object( strplist, index);
}
                                                      
static char *get_inner( char *str, char branch)
// 설명: " 또는 ' 으로 묶인 문자열 값을 구한다.
// 참고: 인용 부호 안에는 공백 문자 이상의 모든 문자를 포함한다.
// 반환: 인수로 받은 문자열 포인터에서 다음 처리할 문자 위치
{                   
    char   *pbuff;                                                              // 버퍼 사용을 위한 포인터
    char    ch_data;                                                            // 검색 대상 문자

    pbuff   = buff_parse;
    
    while( '\0' != *str)
    {
        ch_data = *str++;
        if ( branch == ch_data)                                                 // 구별자 문자를 만났다면
        {  
            break;                                                              // break
        }
        else
        {
           *pbuff++ = ch_data;                                                  // 문자열 복사
        }
    }
   *pbuff = '\0';                                                               // 데이터 구성 완료
    return str;
}

static char *get_string( char *str)
// 설명: 문자열 끝이나 '=' 문자를 만나기 까지 공백없는 문자열을 구한다.
// 반환: 인수로 받은 문자열 포인터에서 다음 처리할 문자 위치
{
    char   *pbuff;                                                              // 버퍼 사용을 위한 포인터
    char    ch_data;                                                            // 검색 대상 문자         

    pbuff   = buff_parse;
    
    while( '\0' != *str)
    {
        
        ch_data = *str;
        if ( ( ' ' == ch_data) || ( '=' == ch_data))
        {  
            break;
        }
        else
        {
           *pbuff++ = ch_data;
        }
        str++;                                                                  // 이 함수 호출 후에 '='문자가 있는지를 확인해야 하므로, 여기서 포인터 증가
    }
   *pbuff = '\0';
    return str;
}

static char *get_parse( char *str)
// 설명: 인수로 받은 문자열을 인용부호와 인용부호가 없는 문자열에 따라 파싱한다.
// 반환: 인수로 받은 문자열 포인터에서 다음 처리할 문자 위치
{
    buff_parse[0] = '\0';

    while( '\0' != *str)
    {
        switch( *str++)
        {                     
            case '\''   :                                                       // 인용부호 ' 문자 사이의 문자열을 구한다.
            {
                str = get_inner( str, '\'');
                return str;
            }
            case '"'    :                                                       // 인용부호 " 문자 사이의 문자열을 구한다.
            {
                str = get_inner( str, '\"');
                return str;
            }
            case ' '    :                                                       // 공백이나
            case '='    :                                                       // 분리자 이면 다음 문자를 계속 검색
                    break;
            default     :
            {
                str = get_string( str-1);                                       // 공백이나 분리자를 만날 때까지의 문자열을 구한다.    
                return str;
            }
        }
    }
    return str;
}

static int is_identify( char *str)
// 설명: 방금 구한 문자열이 구별자인지를 확인한다.
// 참고: 문자열 뒤에 공백이나 분리자만 있다면 구별자로 인정
// 반환: 구별자 여부
{
    while( '\0' != *str)
    {
        switch( *str++)
        {
            case ' '    :   break;                                              // 공백 문자이면 다음 문자를 계속 검색
            case '='    :   return 1;                                           // '=' 문자가 있으면 OK
            default     :   return 0;                                           // 공백이나 '=' 문자가 아니면 FALSE
        }
    }        
    return 0;
}

static void parse_string( tstrlist *lst_parse, char *str)
// 설명: 구별자와 구별자에 대한 데이터를 구한다.
// 반환: 구별자 개수
{
    char   *pdata;
    
    while ( '\0' != *str)
    {
        str = get_parse( str);
        if ( '\0' == buff_parse[0])
        {
            break;
        }
        if ( !is_identify( str))
        {
            continue;
        }
        memcpy( buff_identify, buff_parse, strlen( buff_parse)+1);              // NULL까지 포함하기 위해 +1
        
        str     = get_parse( str);
        pdata   = ( char *)malloc( strlen( buff_parse)+1);
        if ( NULL == pdata)
        {         
            strp_error_code = STRPERR_OUT_OF_MEMORY;
            break;
        }
        else
        {
            memcpy( pdata, buff_parse, strlen( buff_parse)+1);                  // NULL까지 포함하기 위해 +1
            tstrlist_add_object( lst_parse, buff_identify, pdata);
        }            
    }
}

int strp_read_bool( tstrlist *strplist, char *str_identify, int default_value)
/**
    @brief  구별자가 지정하는 Boolean 데이터를 구한다.
    @param  strplist : 파싱 자료를 가지고 있는 tstlist
    @param  str_identify : 구별자 문자열
    @param  default_value : 값이 없다면 대신 반환될 기본값
    @warning    구별자의 문자열이 0 이면 FALSE로 반환하며\n
                이외는 무조건 TRUE로 반환한다.\n
                즉, 구별자가 가지고 있는 문자열 정보가\n
                '0' 인지 아닌지의 여부를 반환한다.
*/
{
    char   *data;
    int     int_data;

    data    = read_string( strplist, 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 strp_read_real( tstrlist *strplist, char *str_identify, double default_value)
/**
    @brief  구별자가 지정하는 정수 데이터를 구한다.
    @param  strplist : 파싱 자료를 가지고 있는 tstlist
    @param  str_identify : 구별자 문자열
    @param  default_value : 값이 없다면 대신 반환될 기본값
    @return
            - 구별자에 해당하는 실수 값
            - 저정한 섹션이나 구별자에 대한 실수 값이 없다면 기본값을 반환
*/
{
    char       *data;
    double      float_data;


    data    = read_string( strplist, 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 strp_read_integer( tstrlist *strplist, char *str_identify, int default_value)
/**
    @brief  구별자가 지정하는 정수 데이터를 구한다.
    @param  strplist : 파싱 자료를 가지고 있는 tstlist
    @param  str_identify : 구별자 문자열
    @param  default_value : 값이 없다면 대신 반환될 기본값
    @return
            - 구별자에 해당하는 정수 값
            - 저정한 섹션이나 구별자에 대한 정수 값이 없다면 기본값을 반환
*/
{
    char   *data;
    int     int_data;

    data    = read_string( strplist, 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 *strp_read_string( tstrlist *strplist, char *str_identify, char *default_value)
/**
    @brief  섹션과 구별자가 지정하는 문자열 데이터를 구한다.
    @param  strplist : 파싱 자료를 가지고 있는 tstlist
    @param  str_identify : 구별자 문자열
    @param  default_value : 값이 없다면 대신 반환될 기본값
    @return\n
        구별자의 문자열 정보\n
        저정한 섹션이나 구별자에 대한 문자열이 없다면 기본값을 반환
    @warning 절대 반환 받은 문자열을 소멸 시켜서는 안 된다!!
*/
{
    char    *data;

    data    = read_string( strplist, str_identify);                             // 먼저 구별자로 데이터를 구한다.    
    if ( NULL == data)                                  return default_value;   // 찾아진 데이터가 없다면 기본값을 반환한다.
    else if ( 0 == strlen( data) )                      return default_value;   // 문자열 데이터가 없다면 기본값을 반환한다.
    else                                                return data;
}

char  *strp_error_string( void)
/**
    @brief  strp_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[strp_error_code]);
}

int strp_print_error( char *remark)
/**
    @brief  ini_error_code에 대한 에러 설명 문자열을 화면에 출력
    @param  remark : 에러 설명 문자열 끝에 첨부하여 출력할 문자열
    @return\n
        에러 코드
*/
{
   printf( "[str parsing error:%d]%s %s\n", strp_error_code, strp_error_string(), remark);
   return strp_error_code;
}

void strp_free( tstrlist *strplist)
/**
    @brief  strparsing 객체를 소멸한다.
    @param  strplist : strparsing 객체
*/
{
    int     ndx;
    char   *pdata;
    
    for ( ndx = 0; ndx < tstrlist_getcount( strplist); ndx++)
    {
        pdata   = ( char *)tstrlist_get_object( strplist, ndx);                 // 객체로 등록한 문자열 제거
        free( pdata);
    }
    tstrlist_free( strplist);                                                   // 리스트 소멸
}
tstrlist *strp_parsing( char *data)
/**
    @brief  data 문자열을 분석해서 구별자와 데이터로 구성된 아이템 목록을 만든다.\n
    @param  data : 문자열 데이터
    @return\n
        구별자와 데이터로 구성된 아이템의 tstrlist *\n
        읽기에 실패했다면 NULL을 반환
*/
{
    tstrlist   *lst_parse;

    strp_error_code  = STRPERR_NONE;                                            //  에러코드: 에러 없음

    lst_parse = tstrlist_create();                                              //  tstrlist 객체 생성
    if ( NULL == lst_parse)                                                     //  tstrlist 객체를 생성하지 못했다면
    {
        strp_error_code  = STRPERR_CREATE_LIST_FAIL;                            //  에러코드: 루트 섹션 리스트 생성
        return  NULL;
    }
    parse_string( lst_parse, data);
    return lst_parse;
}