Эх сурвалжийг харах

T20M5021 #comment 实现对.ini类型文件的读取并添加单元测试TODO:多并发和多进程

gifur 5 жил өмнө
parent
commit
62fe703d28

+ 1 - 1
CMakeSettings.json

@@ -18,7 +18,7 @@
       "configurationType": "Debug",
       "buildRoot": "${projectDir}\\out\\build\\${name}",
       "installRoot": "${projectDir}\\out\\install\\${name}",
-      "cmakeCommandArgs": "-D BUILD_TESTING=OFF",
+      "cmakeCommandArgs": "-D BUILD_TESTING=ON",
       "buildCommandArgs": "",
       "ctestCommandArgs": "-C Debug",
       "inheritEnvironments": [ "msvc_x86" ],

+ 1 - 0
libtoolkit/array.h

@@ -10,6 +10,7 @@ extern "C" {
 #endif
 
 #include <stdarg.h>
+#include <stdlib.h>
 
 typedef struct array_header_t array_header_t;
 

+ 4 - 1
winpr/include/winpr/ini.h

@@ -41,7 +41,7 @@ extern "C"
 
 	WINPR_API const char* IniFile_GetKeyValueString(wIniFile* ini, const char* section,
 	                                                const char* key);
-	WINPR_API int IniFile_GetKeyValueInt(wIniFile* ini, const char* section, const char* key);
+	WINPR_API int IniFile_GetKeyValueInt(wIniFile* ini, const char* section, const char* key, const int defValue);
 
 	WINPR_API int IniFile_SetKeyValueString(wIniFile* ini, const char* section, const char* key,
 	                                        const char* value);
@@ -51,6 +51,8 @@ extern "C"
 	WINPR_API wIniFile* IniFile_New(void);
 	WINPR_API void IniFile_Free(wIniFile* ini);
 
+#ifndef _WIN32
+
 WINPR_API DWORD GetPrivateProfileStringA(LPCSTR lpAppName, LPCSTR lpKeyName, LPCSTR lpDefault,
 		LPSTR lpReturnedString, DWORD nSize, LPCSTR lpFileName);
 
@@ -95,6 +97,7 @@ WINPR_API BOOL WritePrivateProfileSectionW(LPCWSTR lpAppName, LPCWSTR lpString,L
 #define WritePrivateProfileSection  WritePrivateProfileSectionA
 #endif // !UNICODE
 
+#endif //_WIN32
 
 #ifdef __cplusplus
 }

+ 205 - 36
winpr/libwinpr/utils/ini.c

@@ -24,7 +24,9 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#ifndef _WIN32
 #include <unistd.h>
+#endif
 
 #include <errno.h>
 #include <winpr/wtypes.h>
@@ -234,7 +236,7 @@ static wIniFileKey* IniFile_Key_New(const char* name, const char* value)
 	{
 		key->name = _strdup(name);
 		key->value = _strdup(value);
-		key->invalid = TRUE;
+		key->invalid = FALSE;
 
 		if (!key->name || !key->value)
 		{
@@ -271,14 +273,12 @@ static wIniFileSection* IniFile_Section_New(const char* name)
 		return NULL;
 
 	section->name = _strdup(name);
-	section->invalid = TRUE;
-
 	if (!section->name)
 	{
 		free(section);
 		return NULL;
 	}
-
+	section->invalid = FALSE;
 	section->nKeys = 0;
 	section->cKeys = 64;
 	section->keys = (wIniFileKey**)calloc(section->cKeys, sizeof(wIniFileKey*));
@@ -322,7 +322,7 @@ static wIniFileSection* IniFile_GetSection(wIniFile* ini, const char* name)
 	for (index = 0; index < ini->nSections; index++)
 	{
 		if (_stricmp(name, ini->sections[index]->name) == 0 
-			&& !!ini->sections[index]->invalid)
+			&& !ini->sections[index]->invalid)
 		{
 			section = ini->sections[index];
 			break;
@@ -365,6 +365,34 @@ static wIniFileSection* IniFile_AddSection(wIniFile* ini, const char* name)
 	return section;
 }
 
+static BOOL IniFile_RemoveSection(wIniFile* ini, const char* name, BOOL* changed)
+{
+	size_t index;
+	wIniFileSection* section = NULL;
+
+	if (!ini || !name)
+		return FALSE;
+
+	for (index = 0; index < ini->nSections; index++) {
+		if (_stricmp(name, ini->sections[index]->name) == 0) {
+			section = ini->sections[index];
+			break;
+		}
+	}
+	if(section)
+	{
+		ini->nSections--;
+		ini->sections[index] = ini->sections[ini->nSections];
+		ini->sections[ini->nSections] = NULL;
+		IniFile_Section_Free(section);
+		if(changed)
+		{
+			*changed = TRUE;
+		}
+	}
+	return TRUE;
+}
+
 static wIniFileKey* IniFile_GetKey(wIniFile* ini, wIniFileSection* section, const char* name)
 {
 	size_t index;
@@ -386,7 +414,7 @@ static wIniFileKey* IniFile_GetKey(wIniFile* ini, wIniFileSection* section, cons
 }
 
 static wIniFileKey* IniFile_AddKey(wIniFile* ini, wIniFileSection* section, const char* name,
-                                   const char* value)
+                                   const char* value, BOOL* changed)
 {
 	wIniFileKey* key;
 
@@ -418,19 +446,52 @@ static wIniFileKey* IniFile_AddKey(wIniFile* ini, wIniFileSection* section, cons
 
 		section->keys[section->nKeys] = key;
 		section->nKeys++;
+		if (changed) { *changed = TRUE; }
 	}
-	else
+	else if(_stricmp(key->value, value) != 0)
 	{
 		free(key->value);
 		key->value = _strdup(value);
 
 		if (!key->value)
 			return NULL;
+		if (changed) { *changed = TRUE; }
 	}
 
 	return key;
 }
 
+static BOOL IniFile_RemoveKey(wIniFile* ini, const char* sectionName, const char* keyName, BOOL* changed)
+{
+	size_t index;
+	wIniFileKey* key = NULL;
+	wIniFileSection* section = NULL;
+	if (!sectionName || !keyName)
+		return FALSE;
+	section = IniFile_GetSection(ini, sectionName);
+	if(section)
+	{
+		for (index = 0; index < section->nKeys; index++) {
+			if (_stricmp(keyName, section->keys[index]->name) == 0) {
+				key = section->keys[index];
+				break;
+			}
+		}
+		if(key)
+		{
+			section->nKeys--;
+			section->keys[index] = section->keys[section->nKeys];
+			section->keys[section->nKeys] = NULL;
+			IniFile_Key_Free(key);
+			if(changed)
+			{
+				*changed = TRUE;
+			}
+		}
+	}
+	return TRUE;
+}
+
 static int IniFile_Load(wIniFile* ini)
 {
 	char* line;
@@ -494,7 +555,7 @@ static int IniFile_Load(wIniFile* ini)
 
 			value = beg;
 
-			if (!IniFile_AddKey(ini, section, name, value))
+			if (!IniFile_AddKey(ini, section, name, value, NULL))
 				return -1;
 		}
 	}
@@ -649,7 +710,7 @@ const char* IniFile_GetKeyValueString(wIniFile* ini, const char* section, const
 	return value;
 }
 
-int IniFile_GetKeyValueInt(wIniFile* ini, const char* section, const char* key)
+int IniFile_GetKeyValueInt(wIniFile* ini, const char* section, const char* key, const int defValue)
 {
 	int err;
 	long value = 0;
@@ -658,12 +719,12 @@ int IniFile_GetKeyValueInt(wIniFile* ini, const char* section, const char* key)
 	pSection = IniFile_GetSection(ini, section);
 
 	if (!pSection)
-		return 0;
+		return defValue;
 
 	pKey = IniFile_GetKey(ini, pSection, key);
 
 	if (!pKey)
-		return 0;
+		return defValue;
 
 	err = errno;
 	errno = 0;
@@ -671,7 +732,7 @@ int IniFile_GetKeyValueInt(wIniFile* ini, const char* section, const char* key)
 	if ((value < INT_MIN) || (value > INT_MAX) || (errno != 0))
 	{
 		errno = err;
-		return 0;
+		return defValue;
 	}
 	return (int)value;
 }
@@ -689,7 +750,7 @@ int IniFile_SetKeyValueString(wIniFile* ini, const char* section, const char* ke
 	if (!pSection)
 		return -1;
 
-	pKey = IniFile_AddKey(ini, pSection, key, value);
+	pKey = IniFile_AddKey(ini, pSection, key, value, NULL);
 
 	if (!pKey)
 		return -1;
@@ -711,7 +772,7 @@ int IniFile_SetKeyValueInt(wIniFile* ini, const char* section, const char* key,
 	if (!pSection)
 		return -1;
 
-	pKey = IniFile_AddKey(ini, pSection, key, strVal);
+	pKey = IniFile_AddKey(ini, pSection, key, strVal, NULL);
 
 	if (!pKey)
 		return -1;
@@ -842,17 +903,26 @@ void IniFile_Free(wIniFile* ini)
 	free(ini);
 }
 
+#ifndef _WIN32
+
 DWORD GetPrivateProfileStringA(LPCSTR lpAppName, LPCSTR lpKeyName, LPCSTR lpDefault,
 							   LPSTR lpReturnedString, DWORD nSize, LPCSTR lpFileName)
 {
 	wIniFile* ini;
 	DWORD nRetSize = 0;
+	DWORD nRealSize = 0;
 	const char* value;
 	wIniFileSection* pSection = NULL;
 	int index;
 	wIniFileKey* key = NULL;
 	char *t;
 	size_t totalLen = 0;
+
+	if(lpAppName == NULL)
+	{
+		return GetPrivateProfileSectionNamesA(lpReturnedString, nSize, lpFileName);
+	}
+
 	ini = IniFile_New();
 	if(IniFile_ReadFile(ini, lpFileName) < 0) {
 		IniFile_Free(ini);
@@ -862,9 +932,17 @@ DWORD GetPrivateProfileStringA(LPCSTR lpAppName, LPCSTR lpKeyName, LPCSTR lpDefa
 	if(lpKeyName != NULL) {
 		value = IniFile_GetKeyValueString(ini, lpAppName, lpKeyName);
 		if(value) {
-			nRetSize = strlen(value);
-			if(nSize > 0 && lpReturnedString) {
-				strncpy(lpReturnedString, value, nSize > strlen(value)+1 ? strlen(value)+1 : nSize);
+			nRealSize = strlen(value);
+			if(nRealSize +1 > nSize)
+			{
+				nRetSize = nSize - 1;
+			} 
+			else
+			{
+				if (nSize > 0 && lpReturnedString) {
+					strncpy(lpReturnedString, value, strlen(value) + 1);
+				}
+				nRetSize = nRealSize;
 			}
 		}
 	} else { // key == null
@@ -881,7 +959,7 @@ DWORD GetPrivateProfileStringA(LPCSTR lpAppName, LPCSTR lpKeyName, LPCSTR lpDefa
 //            if(totalLen > 0) {
 //                totalLen--;
 //            }
-			nRetSize = totalLen;
+			nRealSize = nRetSize = totalLen;
 			if(totalLen > 1 && nSize >= 2 && lpReturnedString) {
 
 				if(totalLen > nSize) {
@@ -914,11 +992,12 @@ DWORD GetPrivateProfileStringA(LPCSTR lpAppName, LPCSTR lpKeyName, LPCSTR lpDefa
 		}
 	}
 
-	if(nRetSize == 0 && nSize > 0 && lpReturnedString) {
+	if(nRealSize == 0 && nSize > 0 && lpReturnedString) {
 		lpReturnedString[0] = '\0';
 		if(lpDefault) {
-			nRetSize = nSize > strlen(lpDefault)+1 ? strlen(lpDefault)+1 : nSize;
-			strncpy(lpReturnedString, lpDefault, nRetSize);
+			nRealSize = nSize > strlen(lpDefault)+1 ? strlen(lpDefault)+1 : nSize;
+			strncpy(lpReturnedString, lpDefault, nRealSize);
+			nRetSize = strlen(lpReturnedString);
 		}
 	}
 	IniFile_Free(ini);
@@ -945,7 +1024,7 @@ UINT GetPrivateProfileIntA(LPCSTR lpAppName, LPCSTR lpKeyName, INT nDefault, LPC
 		WLog_ERR(TAG, "failed to parse %s", lpFileName);
 		return ret;
 	}
-	ret = IniFile_GetKeyValueInt(ini, lpAppName, lpKeyName);
+	ret = IniFile_GetKeyValueInt(ini, lpAppName, lpKeyName, nDefault);
 	IniFile_Free(ini);
 	return ret;
 }
@@ -1029,21 +1108,49 @@ BOOL WritePrivateProfileStringA(LPCSTR lpAppName, LPCSTR lpKeyName, LPCSTR lpStr
 {
 	wIniFile* ini;
 	BOOL ret = TRUE;
+	BOOL changed = FALSE;
 	ini = IniFile_New();
 	if(!ini) {
 		return FALSE;
 	}
 	if(IniFile_ReadFile(ini, lpFileName) < 0 && access(lpFileName, F_OK) == 0) {
+		printf("open ini file failed.\n");
 		ret = FALSE;
 	} else {
-		if(IniFile_SetKeyValueString(ini, lpAppName, lpKeyName, lpString) < 0) {
-			ret = FALSE;
-		} else {
-			if(IniFile_WriteFile(ini, lpFileName) < 0) {
+		if(lpAppName == NULL)
+		{
+			//TODO:
+		}
+		if(lpKeyName == NULL)
+		{
+			//remove all entries inner section and the section also.
+			ret = IniFile_RemoveSection(ini, lpAppName, &changed);
+		}
+		else if(lpString == NULL)
+		{
+			//remote the specified entry inner section
+			ret = IniFile_RemoveKey(ini, lpAppName, lpKeyName, &changed);
+		}
+		else
+		{
+			if (IniFile_SetKeyValueString(ini, lpAppName, lpKeyName, lpString) < 0) {
 				ret = FALSE;
+			} else
+			{
+				changed = TRUE;
 			}
 		}
 	}
+
+finished:
+
+	if(ret && changed)
+	{
+		if (IniFile_WriteFile(ini, lpFileName) < 0) {
+			ret = FALSE;
+		}
+	}
+
 	IniFile_Free(ini);
 	return ret;
 }
@@ -1058,7 +1165,15 @@ BOOL WritePrivateProfileSectionA(LPCSTR lpAppName, LPCSTR lpString, LPCSTR lpFil
 {
 	wIniFile* ini;
 	BOOL ret = TRUE;
+	BOOL changed = FALSE;
 	wIniFileSection* pSection = NULL;
+	wIniFileKey* pKey = NULL;
+	char* curToken = NULL;
+	char* nextToken = NULL;
+	char* newKey = NULL;
+	char* newValue = NULL;
+	char* newString = NULL;
+	char* keyValue = NULL;
 	ini = IniFile_New();
 	if(!ini) {
 		return FALSE;
@@ -1066,18 +1181,70 @@ BOOL WritePrivateProfileSectionA(LPCSTR lpAppName, LPCSTR lpString, LPCSTR lpFil
 	if(IniFile_ReadFile(ini, lpFileName) < 0) {
 		ret = FALSE;
 	} else {
-		if(lpString == NULL) {
-			//to delete the section...
-			pSection = IniFile_GetSection(ini, lpAppName);
-			if(!pSection) {
-				ret = FALSE;
-			} else {
-				pSection->invalid = TRUE;
+		if(lpAppName != NULL)
+		{
+			if (lpString == NULL) 
+			{
+				printf("to delete the section...\n");
+				ret = IniFile_RemoveSection(ini, lpAppName, &changed);
+			}
+			else
+			{
+				pSection = IniFile_GetSection(ini, lpAppName);
+				if(!pSection)
+				{
+					pSection = IniFile_AddSection(ini, lpAppName);
+					if(!pSection)
+					{
+						ret = FALSE;
+						goto end;
+					}
+					changed = TRUE;
+				}
+				curToken = (char*)&lpString[0];
+				while (curToken != NULL && curToken[0] != '\0') 
+				{
+					keyValue = _strdup(curToken);
+					if (!keyValue) {
+						ret = FALSE;
+						goto end;
+					}
+					newKey = strtok_s(keyValue, "=", &newValue);
+					newValue = strtok_s(NULL, "=", &newValue);
+					pKey = IniFile_GetKey(ini, pSection, newKey);
+					if (pKey == NULL) {
+						pKey = IniFile_AddKey(ini, pSection, newKey, newValue, NULL);
+						changed = TRUE;
+					} else if(_stricmp(pKey->value, newValue) != 0)
+					{
+						free(pKey->value);
+						pKey->value = _strdup(newValue);
+						if (!pKey->value)
+						{
+							free(keyValue);
+							ret = FALSE;
+							goto end;
+						}
+						changed = TRUE;
+					}
+					free(keyValue);
+					//curToken = strtok_s(NULL, "\0", &nextToken);
+					curToken = curToken + strlen(curToken) + 1;
+				}
 			}
 		}
 	}
-	if(ret == TRUE && IniFile_WriteFile(ini, lpFileName) < 0) {
-		ret = FALSE;
+	if(ret == TRUE && changed) {
+		if(IniFile_WriteFile(ini, lpFileName) < 0)
+		{
+			ret = FALSE;
+		}
+	}
+
+end:
+	if(newString != NULL)
+	{
+		free(newString);
 	}
 	IniFile_Free(ini);
 	return ret;
@@ -1087,4 +1254,6 @@ WINPR_API BOOL WritePrivateProfileSectionW(LPCWSTR lpAppName, LPCWSTR lpString,L
 {
 	WLog_ERR(TAG, "%s operation not implemented", __FUNCTION__);
 	return FALSE;
-}
+}
+
+#endif //_WIN32

+ 2 - 2
winpr/libwinpr/utils/test/CMakeLists.txt

@@ -40,10 +40,10 @@ target_link_libraries(${MODULE_NAME} winpr)
 set_target_properties(${MODULE_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${TESTING_OUTPUT_DIRECTORY}")
 
 if(NOT MSVC)
-	set(TEST_DIR "${TESTING_OUTPUT_DIRECTORY}/${MODULE_NAME}Area")
+	set(TEST_DIR "${TESTING_OUTPUT_DIRECTORY}")
 	set(LINE_FEED "\n")
 else()
-	set(TEST_DIR "${TESTING_OUTPUT_DIRECTORY}/${CMAKE_BUILD_TYPE}/${MODULE_NAME}Area")
+	set(TEST_DIR "${TESTING_OUTPUT_DIRECTORY}/${CMAKE_BUILD_TYPE}")
 	set(LINE_FEED "\r\n")
 endif()
 file(MAKE_DIRECTORY "${TEST_DIR}")

+ 238 - 9
winpr/libwinpr/utils/test/TestIni.c

@@ -36,28 +36,240 @@ const char TEST_INI_03[] = "[FreeRDS]\n"
                            "sysconfdir=\"etc\"\n"
                            "\n";
 
-int TestWinPrivateProfile()
+int TestGetPrivateProfileSectionNamesA(const char* iniFileName, const int dream_cnt)
+{
+	int cnt;
+	char* t;
+	char tmp[8192];
+	UINT n;
+	memset(tmp, 0, sizeof(tmp));
+	n = GetPrivateProfileSectionNamesA(tmp, sizeof(tmp), iniFileName);
+	t = tmp;
+	cnt = 0;
+	while (*t != '\0') {
+		cnt++;
+		printf("section: %s\n", t);
+		t += strlen(t) + 1;
+	}
+	if (cnt != dream_cnt) {
+		printf("GetPrivateProfileSectionNamesA: all sections name count should be %d: %d\n", dream_cnt, cnt);
+		return -1;
+	}
+	return 0;
+}
+
+int TestWritPrivateProfile(const char* iniFileName)
+{
+	BOOL ret;
+	UINT n;
+	int cnt;
+	char* t;
+	char tmp[8192];
+	char little_tmp[3] = { 0 };
+
+	/*This operation is atomic; no operations that read from or write to the specified initialization file are allowed
+	 * while the information is being written.
+	 */
+	/*if the lpString is null, it would delete the specified section*/
+	ret = WritePrivateProfileSectionA("AddSection1", "AddKey1=AddValue1\0AddKey2=AddValue2\0\0", iniFileName);
+	if(ret == 0)
+	{
+		printf("WritePrivateProfileSectionA should not be zero!\n");
+		goto error;
+	}
+	n = GetPrivateProfileStringA("AddSection1", "AddKey2", "no value", 
+		tmp, sizeof(tmp), iniFileName);
+	if (n != strlen("AddValue2") || strcmp(tmp, "AddValue2") != 0) {
+		printf("get [AddSection1]'s AddValue2 failed, returned value: %d\n", n);
+		goto error;
+	}
+	if(0 != TestGetPrivateProfileSectionNamesA(iniFileName, 4))
+	{
+		goto error;
+	}
+
+	printf("to WritePrivateProfileStringA\n");
+	ret = WritePrivateProfileStringA("AddSection1", "AddKey1", NULL, iniFileName);
+	memset(tmp, 0, sizeof(tmp));
+	n = GetPrivateProfileStringA("AddSection1", "AddKey1", "no value",
+		tmp, sizeof(tmp), iniFileName);
+	if (n != strlen("no value") || strcmp(tmp, "no value") != 0) {
+		printf("get [AddSection1]'s AddKey1 should failed, returned value: %d\n", n);
+		goto error;
+	}
+
+	ret = WritePrivateProfileStringA("AddSection1", "AddKey3", "AddValue3", iniFileName);
+	n = GetPrivateProfileStringA("AddSection1", "AddKey3", "no value",
+		tmp, sizeof(tmp), iniFileName);
+	if (n != strlen("AddValue3") || strcmp(tmp, "AddValue3") != 0) {
+		printf("get [AddSection1]'s AddKey3 failed, returned value: %d\n", n);
+		goto error;
+	}
+	/*
+	 * the entire section, including all entries within the section, is deleted.
+	 */
+	printf("WritePrivateProfileStringA with null-key and null-value\n");
+	ret = WritePrivateProfileStringA("AddSection1", NULL, NULL, iniFileName);
+
+	memset(tmp, 0, sizeof(tmp));
+	n = GetPrivateProfileStringA("AddSection1", "AddKey2", "no value",
+		tmp, sizeof(tmp), iniFileName);
+	if (n != strlen("no value") || strcmp(tmp, "no value") != 0) {
+		printf("get [AddSection1]'s AddKey2 should failed, returned value: %d\n", n);
+		return -1;
+	}
+
+	if (0 != TestGetPrivateProfileSectionNamesA(iniFileName, 3)) {
+		return -1;
+	}
+
+	ret = WritePrivateProfileSectionA("AddSection1", "AddKey1=AddValue1", iniFileName);
+	if (0 != TestGetPrivateProfileSectionNamesA(iniFileName, 4)) {
+		goto error;
+	}
+
+	printf("WritePrivateProfileSectionA with null key=value\n");
+	ret = WritePrivateProfileSectionA("AddSection1", NULL, iniFileName);
+	if (ret == 0) {
+		printf("WritePrivateProfileSectionA with null should not be zero!\n");
+		return -1;
+	}
+
+	if(0 != TestGetPrivateProfileSectionNamesA(iniFileName, 3))
+	{
+		return -1;
+	}
+	return 0;
+
+error:
+	WritePrivateProfileSectionA("AddSection1", NULL, iniFileName);
+	return -1;
+}
+
+int TestWinPrivateProfile(const char* iniFileName)
 {
 	UINT n;
 	char buf[240] = { 0 };
-	const char* iniFileName = "./TestWinPRUtils/ini_test.ini";
+	/*cannot be pure filename.*/
+	printf("to test Get/Set PrivateProfile serial function\n");
+	/*by the way: this function implemented at dllini.c at windows platform.*/
 	n = GetPrivateProfileIntA("Section1", "KeyInt1", 0, iniFileName);
 	if(n != 1)
 	{
-		printf("get [Section1]'s KeyInt1 is not the dream one, return value: %d\n", n);
+		printf("case1: get [Section1]'s KeyInt1 is not the dream one, return value: %d\n", n);
 		return -1;
 	}
 	n = GetPrivateProfileIntA("Section1", "KeyInt2", 4, iniFileName);
 	if (n != 4) {
-		printf("get [Section1]'s KeyInt2 should be returned default one, return value: %d\n", n);
+		printf("get [Section1]'s KeyInt2 should be returned default 4, return value: %d\n", n);
 		return -1;
 	}
+
+	{
+		char tmp[8192];
+		char little_tmp[3] = {0};
+		char* p;
+		char* t;
+		int cnt;
+		tmp[0] = 0;
+		n = GetPrivateProfileStringA("Section3", "KeyString3", "no value", tmp, sizeof(tmp), iniFileName);
+		if(n != strlen("Value3") || strcmp(tmp, "Value3") != 0)
+		{
+			printf("get [Section3]'s KeyString3 failed, returned value: %d\n", n);
+			return -1;
+		}
+		/*
+		 *If neither lpAppName nor lpKeyName is NULL and the supplied destination buffer is too small 
+		 *to hold the requested string, the string is truncated and followed by a null character,
+		 * and the return value is equal to nSize minus one.
+		 */
+		n = GetPrivateProfileStringA("Section3", "KeyString3", "no value", little_tmp, sizeof(little_tmp), iniFileName);
+		if(n != sizeof(little_tmp) -1)
+		{
+			printf("get [Section3]'s KeyString3 should return minus one bcz the buffer is too small: %d\n", n);
+			return -1;
+		}
+
+		memset(tmp, 0, sizeof(tmp));
+		n = GetPrivateProfileStringA("Section3", "KeyStrNotExist", "no value", tmp, sizeof(tmp), iniFileName);
+		if (n != strlen("no value") || strcmp(tmp, "no value") != 0) {
+			printf("get [Section3]'s KeyStrNotExist failed, returned value: %d\n", n);
+			return -1;
+		}
+
+		memset(tmp, 0, sizeof(tmp));
+		/*the GetPrivateProfileString function copies all section names in the file to the supplied buffer.*/
+		n = GetPrivateProfileStringA(NULL, "KeyStrNotExist", "no value", tmp, sizeof(tmp), iniFileName);
+		t = tmp;
+		cnt = 0;
+		while(*t != '\0')
+		{
+			cnt++;
+			printf("section: %s\n", t);
+			t += strlen(t) + 1;
+		}
+		if(cnt != 3)
+		{
+			printf("all sections name count should be 3: %d\n", cnt);
+			return -1;
+		}
+
+		memset(little_tmp, 0, sizeof(little_tmp));
+		/*
+		 * If either lpAppName or lpKeyName is NULL and the supplied destination buffer is too small
+		 *  to hold all the strings, the last string is truncated and followed by two null characters. 
+		 *  In this case, the return value is equal to nSize minus two.
+		 */
+		n = GetPrivateProfileStringA("Section3", NULL, "", little_tmp, sizeof(little_tmp), iniFileName);
+		if(n != sizeof(little_tmp)-2)
+		{
+			printf("when key is null and buffer is too small, should returned nSize - 2: %d\n", n);
+			return -1;
+		}
+
+		memset(tmp, 0, sizeof(tmp));
+		/*all key names in the section specified by the lpAppName parameter are copied to the buffer*/
+		n = GetPrivateProfileStringA("Section3", NULL, "", tmp, sizeof(tmp), iniFileName);
+		t = tmp;
+		cnt = 0;
+		while (*t != '\0') {
+			cnt++;
+			printf("[Section3].eachKey: %s\n", t);
+			t += strlen(t) + 1;
+		}
+		if (cnt != 3) {
+			printf("all key name count under [Section3] should be 3: %d\n", cnt);
+			return -1;
+		}
+
+		memset(little_tmp, 0, sizeof(little_tmp));
+		/*Retrieves the names of all sections in an initialization file.*/
+		n = GetPrivateProfileSectionNamesA(little_tmp, sizeof(little_tmp), iniFileName);
+		if(n != sizeof(little_tmp)-2)
+		{
+			printf("when buffer is too small, should returned nSize - 2: %d\n", n);
+			return -1;
+		}
+		memset(tmp, 0, sizeof(tmp));
+		n = GetPrivateProfileSectionNamesA(tmp, sizeof(tmp), iniFileName);
+		t = tmp;
+		cnt = 0;
+		while (*t != '\0') {
+			cnt++;
+			printf("section: %s\n", t);
+			t += strlen(t) + 1;
+		}
+		if (cnt != 3) {
+			printf("GetPrivateProfileSectionNamesA: all sections name count should be 3: %d\n", cnt);
+			return -1;
+		}
+	}
 	return 0;
 }
 
 int TestIni(int argc, char* argv[])
 {
-	int i, j;
+	int i, j, n;
 	int nKeys;
 	int nSections;
 	UINT32 iValue;
@@ -65,6 +277,11 @@ int TestIni(int argc, char* argv[])
 	const char* sValue;
 	char** keyNames;
 	char** sectionNames;
+#ifdef _WIN32
+	const char* iniFileName = ".\\ini_test.ini";
+#else
+	const char* iniFileName = "./ini_test.ini";
+#endif
 	/* First Sample */
 	ini = IniFile_New();
 	IniFile_ReadBuffer(ini, TEST_INI_01);
@@ -85,7 +302,7 @@ int TestIni(int argc, char* argv[])
 	}
 
 	free(sectionNames);
-	iValue = IniFile_GetKeyValueInt(ini, "first_section", "one");
+	iValue = IniFile_GetKeyValueInt(ini, "first_section", "one", 0);
 
 	if (iValue != 1)
 	{
@@ -93,7 +310,7 @@ int TestIni(int argc, char* argv[])
 		return -1;
 	}
 
-	iValue = IniFile_GetKeyValueInt(ini, "first_section", "five");
+	iValue = IniFile_GetKeyValueInt(ini, "first_section", "five", 0);
 
 	if (iValue != 5)
 	{
@@ -158,6 +375,18 @@ int TestIni(int argc, char* argv[])
 
 	IniFile_Free(ini);
 
-	return TestWinPrivateProfile();
-	//return 0;
+	n =  TestWinPrivateProfile(iniFileName);
+	if(0 == n)
+	{
+		n = TestWritPrivateProfile(iniFileName);
+	}
+	if(n == 0)
+	{
+		printf("test pass.\n");
+	}
+	else
+	{
+		fprintf(stderr, "test failed.\n");
+	}
+	return n;
 }