#include "stdafx.h"
#include "PhoneDB.h"
#include "delimstrings.h"


#define PHONE_DB_MAP_OBJECT_NAME TEXT("Osisp_lab4, PhoneDB. Tsar Art & Turuta Sa 851002")


// must be NULL if db is not opened!
static HANDLE			g_hFileMapping = NULL;
static const char		*g_DbBeginPtr = NULL;
static const char		*g_DbLimitPtr = NULL;
static BOOL				g_DatabaseOpened = FALSE;
static int				g_CountOfRecords = 0;



BOOL APIENTRY 
DllMain( HMODULE hModule,
         DWORD  ul_reason_for_call,
         LPVOID lpReserved )
{
	switch (ul_reason_for_call)
	{
	case DLL_PROCESS_ATTACH:
		break;

	case DLL_THREAD_ATTACH:
		break;

	case DLL_THREAD_DETACH:
		break;

	case DLL_PROCESS_DETACH:
		if (g_DatabaseOpened)
			CloseDatabase();
		break;
	}
	return TRUE;
}


PHONEDB_API const char*
OpenDatabase(const TCHAR *filename, int *cRecordsPtr)

#define RETURN(ret)\
		do {\
			if (ret == NULL)\
				g_DatabaseOpened = FALSE;\
			else\
				g_DatabaseOpened = TRUE;\
			g_DbBeginPtr = ret;\
			return ret;\
		} while(0)
{
	if (g_DatabaseOpened)
		return NULL; //do nothing, so don't use RETURN macro

	HANDLE	hFile = CreateFile(
		filename,
		GENERIC_READ,
		FILE_SHARE_READ, 
		NULL,
		OPEN_EXISTING,
		FILE_ATTRIBUTE_NORMAL,
		NULL);

	if (hFile == INVALID_HANDLE_VALUE)
		RETURN(NULL);
 
	LARGE_INTEGER	fileSize;
	if (GetFileSizeEx(hFile, &fileSize) == FALSE) {
		CloseHandle(hFile);
		RETURN(NULL);
	}

	g_hFileMapping = CreateFileMapping(
		hFile,
		NULL,
		PAGE_READONLY,
		fileSize.HighPart, fileSize.LowPart,
		PHONE_DB_MAP_OBJECT_NAME);

	if (g_hFileMapping == NULL) {
		CloseHandle(hFile);
		RETURN(NULL);
	}

	const char *retval;
	retval = (const char*)MapViewOfFile(
		g_hFileMapping,
		FILE_MAP_READ,
		0, 0, 0);

	if (retval == NULL) {
		CloseHandle(g_hFileMapping);
		g_hFileMapping = NULL;
		CloseHandle(hFile);
	} else {
		g_DbBeginPtr = retval;
		g_DbLimitPtr = (const char*)((char*)g_DbBeginPtr + fileSize.LowPart);
		g_CountOfRecords = 0;

		for (const char *c = g_DbBeginPtr; c < g_DbLimitPtr; c++)
			if (*c == '\n')
				g_CountOfRecords++;

		if (cRecordsPtr)
			*cRecordsPtr = g_CountOfRecords;
	}

	RETURN(retval);
#undef RETURN
}


PHONEDB_API BOOL
CloseDatabase(void)
{
	if (!g_DatabaseOpened)
		return FALSE;
	
	if (UnmapViewOfFile(g_DbBeginPtr) == FALSE)
		return FALSE;
	
	CloseHandle(g_hFileMapping);

	g_hFileMapping = NULL;
	g_DbBeginPtr = NULL;
	g_DbLimitPtr = NULL;
	g_DatabaseOpened = NULL;
	g_CountOfRecords = 0;

	return TRUE;
}


PHONEDB_API BOOL 
SearchInDatabase(PHONE_DB_RECORD *foundRecordPtr, 
				 const PHONE_DB_RECORD *templateRecordPtr,
				 int cEqualFieldsNeed)

#define MAKE_COPY(field_name)\
	cchCpied = DelimStrCpy(foundRecordPtr->field_name, searchPos, ";\n\r",\
			g_DbLimitPtr, _countof(foundRecordPtr->field_name));\
		\
		foundRecordPtr->field_name[cchCpied-1] = '\0';\
		if (cchCpied == 0)\
			return FALSE;\
		\
		searchPos += cchCpied;\
		if (searchPos[-1] == '\n')\
			goto end_of_record_reached;
{
	static const char *searchEndPos = NULL;
	
	if (foundRecordPtr == NULL) {
		searchEndPos = g_DbBeginPtr;
		return TRUE;
	}
	if (searchEndPos == NULL)
		searchEndPos = g_DbBeginPtr;

	foundRecordPtr->phone[0] = '\0';
	foundRecordPtr->lastname[0] = '\0';
	foundRecordPtr->name[0] = '\0';
	foundRecordPtr->patronym[0] = '\0';
	foundRecordPtr->street[0] = '\0';
	foundRecordPtr->house[0] = '\0';
	foundRecordPtr->housing[0] = '\0';
	foundRecordPtr->apartment[0] = '\0';

	const char *searchPos = searchEndPos;
	BOOL retval = FALSE;
	while (searchPos < g_DbLimitPtr) {
			int cchCpied;

		MAKE_COPY(phone);
		MAKE_COPY(lastname);
		MAKE_COPY(name);
		MAKE_COPY(patronym);

		MAKE_COPY(street);
		MAKE_COPY(house);
		MAKE_COPY(housing);
		MAKE_COPY(apartment);
		
		for (; *searchPos != '\n' && searchPos < g_DbLimitPtr; searchPos++)
			;
end_of_record_reached:

		int cEqualFields = 0;

		#define MAKE_COMPARE(field_name)\
		if (templateRecordPtr->field_name[0] != '\0')\
			cEqualFields += !lstrcmpiA(foundRecordPtr->field_name, templateRecordPtr->field_name)

		MAKE_COMPARE(phone);
		MAKE_COMPARE(lastname);
		MAKE_COMPARE(name);
		MAKE_COMPARE(street);

		MAKE_COMPARE(patronym);
		MAKE_COMPARE(house);
		MAKE_COMPARE(housing);
		MAKE_COMPARE(apartment);

		#undef MAKE_COMPARE

		if (cEqualFields >= cEqualFieldsNeed) {
			retval = TRUE;
			break;
		}
	}
	searchEndPos = searchPos;
	return retval;
#undef MAKE_COPY
}


inline void FillRecordField(char *dest, const char *src, int maxFieldCch)
{
	if (src != NULL) {
		strncpy(dest, src, maxFieldCch);
		dest[maxFieldCch-1] = '\0';
	} else
		dest[0] = '\0';
}

PHONEDB_API void
FillDatabaseRecord(
	PHONE_DB_RECORD *recordPtr,
	const char *phone,
	const char *lastname,
	const char *name,
	const char *patronym,
	const char *street,
	const char *house,
	const char *housing,
	const char *apartment)

#define FILL_FIELD(field_name)\
	FillRecordField(recordPtr->field_name,\
					field_name,\
					_countof(recordPtr->field_name))
{
	FILL_FIELD(phone);
	FILL_FIELD(lastname);
	FILL_FIELD(name);
	FILL_FIELD(patronym);
	FILL_FIELD(street);
	FILL_FIELD(house);
	FILL_FIELD(housing);
	FILL_FIELD(apartment);
#undef FILL_FIELD
}
Соседние файлы в папке PhoneDB