/**
* @file CM_IniFile.c
* @brief 读取ini配置文件
* @author GT-BU
* @date 2021.02.01
* @version V1.0
* @copyright TCT
* @par 修改日志
* <table>
* <tr><th>Date        <th>Version  <th>Author     <th>Description
* <tr><td>2021.02.01  <td>V1.0     <td>GT-BU      <td>创建初始版本
* </table>
*/
#include "CM_IniFile.h"
#include "PFM_Log.h"
#if QNX
#else
#include "cp_interface.h"
#endif

#define KEYVALLEN 100

static CM_INT32 s_isspace(IN CM_CHAR c);

/**
* @brief 判断字符是否为空格
* @param c 输入字符
* @return 判断结果
*  - 1  是空格
*  - 0  不是空格
* @details
* ' ','\f'，'\n','\r'，'\t','\v' 都视作空格
*/
static CM_INT32 s_isspace(IN CM_CHAR c)
{
    CM_INT32 rt = 0;
    /*- 初始化判断结果为0 */
    /*- 判断输入是否属于“空格”字符 */
    if ((' ' == c) || ('\f' == c) || ('\n' == c) || ('\r' == c) || ('\t' == c) || ('\v' == c))
    {
        /*- 判断结果为1*/
        rt = 1;
    }
    else
	{
		/*- 无处理 */
	}
    /*- 返回结果 */
    return rt;
}

/**
* @brief 删除左边的空格
* @param szInput 输入字符串
* @param szOutput 输出字符串
* @details
* 将输入字符串去除左端空格后的内容，复制到输出字符串
*/
void l_trim(OUT CM_CHAR *szOutput, IN const CM_CHAR *szInput)
{
    /*- 输入合法性检查 */
	CM_NM_ASSERT(szInput != NULL, INIFILE_MODE, DARK_FAULT_CODE_FUN_ORDER_1, TSCP_DARK_ASSERT_1);
	CM_NM_ASSERT(szOutput != NULL, INIFILE_MODE, DARK_FAULT_CODE_FUN_ORDER_1, TSCP_DARK_ASSERT_2);
	CM_NM_ASSERT(szOutput != szInput, INIFILE_MODE, DARK_FAULT_CODE_FUN_ORDER_1, TSCP_DARK_ASSERT_3);
    /*- @alias 找到输入字符串左起第一个非空格 */
    while(1)
    {
    	if((*szInput != '\0') && (s_isspace(*szInput)))
    	{
    		++szInput;    /* parasoft-suppress MISRA2004-17_1 MISRA2004-17_4 "提高代码执行效率" */
    	}
    	else
    	{
    		/*- 跳出 */
    		break;
    	}
    }
    /*- 将第一个非空格及右边剩余的字符串复制到输出 */
    (void)strcpy(szOutput, szInput);
}

/**
* @brief 删除左右两边的空格
* @param szInput 输入字符串
* @param szOutput 输出字符串
* @details
* 将输入字符串去除左右端空格后的内容，复制到输出字符串
*/
void a_trim(OUT CM_CHAR *szOutput, IN const CM_CHAR *szInput)
{
    CM_CHAR *p = NULL;
    /*- 输入合法性检查 */
    CM_NM_ASSERT(szInput != NULL, INIFILE_MODE, DARK_FAULT_CODE_FUN_ORDER_2, TSCP_DARK_ASSERT_1);
    CM_NM_ASSERT(szOutput != NULL, INIFILE_MODE, DARK_FAULT_CODE_FUN_ORDER_2, TSCP_DARK_ASSERT_2);
    /*- 去除左端的空格 */
    l_trim(szOutput, szInput);
    /*- @alias 去除右端的空格 */
    for (p = (szOutput + strlen(szOutput)) - 1u; (p >= szOutput) && (s_isspace(*p)); --p)  /* parasoft-suppress MISRA2004-17_1 MISRA2004-17_4 "提高代码执行效率" */
    {
        ;
    }
    *(++p) = '\0'; /* parasoft-suppress MISRA2004-17_4 "提高代码执行效率" */
}

/**
* @brief 读取指定的字符串键值
* @param profile 配置文件路径
* @param appName 块名
* @param keyName 键名
* @param keyVal  键值
* @return 返回值
* - ENUM_CM_TRUE 找到了
* - ENUM_CM_FALSE 没找到
* @details
* 配置文件单行长度不超过100字节
*/
ENUM_CM_RETURN CM_GetProfileString(IN const CM_CHAR *profile, IN const CM_CHAR *appName, IN const CM_CHAR *keyName, OUT CM_CHAR *keyVal)
{
    /*- 变量初始化 */
    CM_CHAR appnamebuf[32] = { 0 };  /* 块名，带[] */
    CM_CHAR keynamebuf[32] = { 0 };  /* 缓存文件中读出的键名 */
    CM_CHAR *pBuf = NULL;            /* 临时变量：字符指针 */
    CM_CHAR *pTmp = NULL;            /* 临时变量：字符指针 */
    CM_CHAR buf_i[KEYVALLEN] = { 0 }; /* 临时变量：字符串缓冲区 */
    CM_CHAR buf_o[KEYVALLEN] = { 0 }; /* 临时变量：字符串缓冲区 */
    FILE *pfile = NULL;      /* 文件指针 */
    CM_INT32 found = 0;   /* 1 appName 2 keyName */
    ENUM_CM_RETURN rt = ENUM_CM_FALSE; /* 函数返回值 */

    /*- 打开配置文件 */
    CM_NM_ASSERT(profile != NULL, INIFILE_MODE, DARK_FAULT_CODE_FUN_ORDER_3, TSCP_DARK_ASSERT_1);
#if QNX
    pfile = fopen(profile, "r");
#else
    CM_CHAR WIN32_profile[1024] = {0};
    strcat(&WIN32_profile, p_exe_path);
    strcat(&WIN32_profile, profile);
    pfile = fopen(WIN32_profile, "r");
#endif
    /*- 是否成功打开配置文件 */
    if (pfile != NULL)
    {
        /*- 准备块名 */
        (void)fseek(pfile, (long)0, SEEK_SET);
        (void)CM_Memset(appnamebuf, 0u, sizeof(appnamebuf),sizeof(appnamebuf));
        CM_NM_ASSERT(appName != NULL, INIFILE_MODE, DARK_FAULT_CODE_FUN_ORDER_3, TSCP_DARK_ASSERT_2);
        (void)sprintf(appnamebuf, "[%s]", appName);

        /*- 按行循环读出配置文件 */
        while ((!feof(pfile)) && (fgets(buf_i, KEYVALLEN, pfile) != NULL)) /* parasoft-suppress MISRAC2012-RULE_13_5-a MISRAC2012-RULE_15_4-a "提高代码效率，只在初始化阶段使用，无安全风险" */
        {
            /*- 去除行左边的空格 */
            l_trim(buf_o, buf_i);
            /*- 字符串长度是否大于0 */
            if (strlen(buf_o) > 0u)
            {
                /*- 检查去除左边空格后的字符串 */
                pBuf = buf_o;
                /*- found标记是否为0 */
                if (found == 0)
                {
                    /*- 是否不是'[' */
                    if (pBuf[0] != '[')
                    {
                        /*- 继续读取下一行 */
                    }
                    /*- 是否与块名一致 */
                    else if (strncmp(pBuf, appnamebuf, strlen(appnamebuf)) == 0)
                    {
                        /*- found标记置1 */
                        found = 1;
                    }
                    else
                    {
                    	/*- 无处理 */
                    }
                }
                /*- found标记是否为1 */
                else if (found == 1)
                {
                    /*- 本行是否为注释 */
                    if (pBuf[0] == '#')
                    {
                        /*- 继续读取下一行 */
                    }
                    /*- 本行是否为新的块标志 */
                    else if (pBuf[0] == '[')
                    {
                        /*- 没找到，退出循环 */
                        break;
                    }
                    else
                    {
                    	/*- 本行中是否有'=' */
                    	pTmp = (CM_CHAR*)strchr(pBuf, '=');
                        if (pTmp != NULL)
                        {
                            /*- 提取‘=’左边的字符串为键名 */
                            (void)CM_Memset(keynamebuf, 0u, sizeof(keynamebuf), sizeof(keynamebuf));
                            (void)sscanf(pBuf, "%[^=|^ |^\t]", keynamebuf);
                            /*- 提取到的键名是否与要查找的键名一致 */
                            if (strcmp(keynamebuf, keyName) == 0)
                            {
                                /*- 提取'='右边的字符串，去除两侧空格后输出 */
                                (void)sscanf(pTmp, "=%[^\n]", buf_i);
                                a_trim(keyVal, buf_i);
                                /*- found标记置2 */
                                found = 2;
                                /*- 退出循环 */
                                break;
                            }
                            else
                            {
                                /*- 无处理 */
                            }
                        }
                        else
                        {
                        	/*- 无处理 */
                        }
                    }
                }
                else
                {
                    /*- 无处理 */
                }
            }
            else
			{
				/*- 无处理 */
			}
        }/* end while */
        (void)fclose(pfile);
    }
    else
    {
        /*- 打开配置文件失败，宕机 */
    	CM_NM_ASSERT(0, INIFILE_MODE, DARK_FAULT_CODE_FUN_ORDER_3, TSCP_DARK_ASSERT_3);
    }
    /*- found标记是否为2 */
    if (2 == found)
    {
        /*- 函数返回值置1 */
        rt = ENUM_CM_TRUE;
    }
    else
	{
		/*- 无处理 */
	}
    /*- 输出返回值 */
    return rt;
}

/**
* @brief 读取指定的整型键值
* @param profile 配置文件路径
* @param appName 块名
* @param keyName 键名
* @return 键值
* - 没找到时返回0
* @details
* 配置文件单行长度不超过100字节
*/
CM_INT32 CM_GetProfileInt(IN const CM_CHAR *profile, IN const CM_CHAR *AppName, IN const CM_CHAR *KeyName)
{
    CM_CHAR s[KEYVALLEN] = { 0 }; /* 临时变量：字符串 */
    CM_INT32 rt = 0; /* 函数返回值 */
    ENUM_CM_RETURN ret = ENUM_CM_FALSE; /* 函数返回值 */
    /*- 读取键值字符串 */
    CM_NM_ASSERT(profile != NULL, INIFILE_MODE, DARK_FAULT_CODE_FUN_ORDER_4,TSCP_DARK_ASSERT_1);
    CM_NM_ASSERT(AppName != NULL, INIFILE_MODE, DARK_FAULT_CODE_FUN_ORDER_4,TSCP_DARK_ASSERT_2);
    CM_NM_ASSERT(KeyName != NULL, INIFILE_MODE, DARK_FAULT_CODE_FUN_ORDER_4,TSCP_DARK_ASSERT_3);
    ret = CM_GetProfileString(profile, AppName, KeyName, s);
    /*- 是否找到了键值字符串 */
    if (ENUM_CM_TRUE == ret)
    {
        /*- 将键值字符串转为整型变量作为函数返回值 */
        rt = (CM_INT32)atoi(s);
    }
    else
	{
		/*- 无处理 */
	}
    /*- 输出返回值 */
    return rt;
}

/**
* @brief 读取指定的HEX键值
* @param profile 配置文件路径
* @param appName 块名
* @param keyName 键名
* @return 键值
* - 没找到时返回0
* @details
* 配置文件单行长度不超过100字节
*/
CM_UINT32 CM_GetProfileHex(IN const CM_CHAR *profile, OUT const CM_CHAR *AppName, IN const CM_CHAR *KeyName)
{
    CM_CHAR s[KEYVALLEN] = { 0 };/* 临时变量：字符串 */
    ENUM_CM_RETURN ret = 0;  /* 临时变量 */
    CM_UINT32 val = 0u;/* 函数返回值 */
    /*- 读取键值字符串 */
    CM_NM_ASSERT(profile != NULL, INIFILE_MODE, DARK_FAULT_CODE_FUN_ORDER_5, TSCP_DARK_ASSERT_1);
    CM_NM_ASSERT(AppName != NULL, INIFILE_MODE, DARK_FAULT_CODE_FUN_ORDER_5, TSCP_DARK_ASSERT_2);
    CM_NM_ASSERT(KeyName != NULL, INIFILE_MODE, DARK_FAULT_CODE_FUN_ORDER_5, TSCP_DARK_ASSERT_3);
    ret = CM_GetProfileString(profile, AppName, KeyName, s);
    /*- 是否找到了键值字符串 */
    if (ENUM_CM_TRUE == ret)
    {
        /*- 将键值字符串按HEX格式转为整型变量作为函数返回值 */
        (void)sscanf(s, "%x", &val);
    }
    else
	{
		/*- 无处理 */
	}
    /*- 输出返回值 */
    return val;
}

/**
* @brief 读取指定文件
* @param profile 文件名
* @param offset 文件偏移量
* @param len 要读取的内容长度
* @param pFileBuf 读取文件的存放的buf
* @return 成功时返回1
* - 失败时返回0
* @details
*/

CM_INT32 CM_ReadFile(IN const CM_CHAR *profile, IN CM_UINT32 offset, IN CM_INT64 len, OUT CM_UINT8 *pFileBuf)
{
	 FILE *pfile = NULL;      /* 文件指针 */
	 CM_UINT64 fileSize = 0u;
	 CM_INT32 rtn = 0;
	 /*- 打开文件 */
	 CM_NM_ASSERT(profile != NULL, INIFILE_MODE, DARK_FAULT_CODE_FUN_ORDER_6, TSCP_DARK_ASSERT_1);
	 pfile = fopen(profile, "r");
	 if((NULL != profile)&&(NULL != pFileBuf)&&(NULL != pfile))
	 {
		(void)fseek(pfile, (long int)0, SEEK_END);
		/*- 获取文件长度*/
		fileSize = (CM_UINT64)ftell(pfile);
	    if(((CM_UINT64)len + (CM_UINT64)offset) <= fileSize)
	    {
	    	(void)fseek(pfile, (CM_INT64)offset, SEEK_SET);
		    /*- 读取文件*/
		    if(0 == fread(pFileBuf, (CM_UINT64)len, 1u, pfile))
		    {
		    	rtn = 0;
		    }
		    else
		    {
		    	rtn = 1;
		    }
	    }
	    else
	    {

	    }

	 }
	 else
	 {

	 }

	 if(NULL == pfile)
	 {
		 /*- 无处理 */
	 }
	 else
	 {
		 /*- 关闭文件 */
		 (void)fclose(pfile);
	 }
	 return rtn;
}

/**
* @brief 读取指定文件
* @param pfile 文件描述符
* @param pFileBuf 读取文件的存放的buf
* @param len 要读取的内容长度
* @return 成功时返回1
* - 失败时返回0
* @details
*/

CM_INT32 CM_ReadOpenFile(IN  FILE *pfile, OUT CM_UINT8 *pFileBuf ,IN CM_INT64 len )
{
	 CM_INT32 rtn = 0;

	 if((NULL != pfile)&&(NULL != pFileBuf))
	 {
		/*- 读取文件*/
		if(0u == fread(pFileBuf, (CM_UINT64)len, 1u, pfile))
		{
			rtn = 0;
		}
		else
		{
			rtn = 1;
		}
	 }
	 else
	 {

	 }
	 return rtn;
}

/**
* @brief 获取文件大小
* @param profile 文件名
* @return 文件大小
* - 没找到时返回0
*/
CM_INT64 CM_GetFileSize(IN const CM_CHAR *profile)
{
	 FILE *pfile = NULL;      /* 文件指针 */
	 CM_INT64 fileSize = 0;
	 /*- 打开文件 */
	 CM_NM_ASSERT(profile != NULL, INIFILE_MODE, DARK_FAULT_CODE_FUN_ORDER_7, TSCP_DARK_ASSERT_1);
	 pfile = fopen(profile, "r");
	 if((NULL != profile)&&(NULL != pfile))
	 {
		(void)fseek(pfile, (CM_INT64)0, SEEK_END);
		/*- 获取文件长度*/
		fileSize = ftell(pfile);
		/*- 如果获取文件长度失败，返回长度为0*/
		if(-1 == fileSize)
		{
			fileSize = 0;
		}
		else
		{

		}
		/*- 关闭文件 */
		(void)fclose(pfile);
	 }
	 else
	 {

	 }
	 return fileSize;
}
