Thread: Back again
View Single Post
Old 05-07-2005, 12:19 PM  
darkone
Disabled
 
darkone's Avatar
 
Join Date: Dec 2001
Posts: 2,230
Default

Just to show off, how trivial it's to write database modules for the new interface, I decided to publish source of current file database module (still work in progress = incomplete notepad draft) But it gives you idea, how much (or should I say little) work it's to write eg. SQL module.

Code:
LPWSTR *TokenizeCommaSeperatedString(LPWSTR wszInput, PULONG pStringCount)
{
	PWCHAR	pFrom, pTo, pBegin;
	WCHAR	wCurrent;
	LPVOID	lpMemory;
	BOOL	bBackSlash		= FALSE;
	ULONG	lResultSize		= 16;
	ULONG	lResultCount	= 0;
	LPWSTR	*wszResult		= 0;

	/* tokenize comma seperated string */
	wszResult	= (LPWSTR *)Allocate("Tokenized string", sizeof(LPWSTR) * lResultSize);
	if (! wszResult) {
		/* out of memory */
		return 0;
	}

	for (pFrom = pBegin = pTo = wszInput;;++pFrom) {
		switch ((wCurrent = pFrom[0])) {
		case L',':
			if (bBackSlash) {
				/* escaped comma */
				break;
			}
		case L'\0':
			if (bBackSlash) {
				/* escaped nul.. decode failure */
				Free(wszResult);
				return 0;
			}
			if (lResultCount == lResultSize) {
				lpMemory	= ReAllocate(wszResult, 0, sizeof(LPWSTR) * (lResultSize + 16));
				if (! lpMemory) {
					/* out of memory */
					Free(wszResult);
					return 0;
				}
				lResultSize	+= 16;
				wszResult	= (LPWSTR *)lpMemory;
			}
			wszResult[lResultCount++]	= pBegin;
			if (wCurrent == L'\0') {
				/* nul char */
				pTo[0]	= L'\0';
				return wszResult;
			}
			pTo[0]	= L'\0';
			pTo		= &pFrom[1];
			pBegin	= pTo;
			continue;
		case L'\\':
			/* escape character */
			if (bBackSlash) {
				/* escaped escape character */
				break;
			}
			bBackSlash	= TRUE;
			continue;
		}
		bBackSlash	= FALSE;
		if (pTo != pFrom) {
			pTo++[0]	= wCurrent;
			continue;
		}
		pTo++;
	}
}


LONG EscapeStringCommas(LPWSTR wszInput, LPWSTR wszOutput, ULONG lOutputSize)
{
	WCHAR	wCurrent;
	PWCHAR	pFrom, pTo;
	LPWSTR	wszResult;

	/* escape string commas */
	for (pFrom = wszInput, pTo = wszOutput;;pFrom++,pTo++) {
		switch ((wCurrent = pFrom[0])) {
		case L'\0':
			return pTo - wszOutput;
		case L'\\':
			/* escape character */
			if (lOutputSize < 2) {
				/* out of buffer space */
				break;
			}
			pTo++[0]	= L'\\';
			pTo++[0]	= L'\\';
			lOutputSize	-= 2;
			continue;
		case L',':
			/* comma */
			if (lOutputSize < 2) {
				/* out of buffer space */
				break;
			}
			pTo++[0]	= L'\\';
			pTo++[0]	= L',';
			lOutputSize	-= 2;
			continue;
		default:
			if (! lOutputSize) {
				/* out of buffer space */
				break;
			}
			pTo++[0]	= wCurrent;
			lOutputSize--;
            continue;
		}
		break;
	}
	return -1;
}


BOOL LockCollection(LPDATABASE lpDatabase, LPDATABASE_COLLECTION *lpCollection)
{
	/* lock and synchronize collection - does nothing for now */
	return TRUE;
}


BOOL CommitCollectionChanges(LPDATABASE lpDatabase, LPDATABASE_COLLECTION *lpCollection)
{
	LPDATABASE_ROW		lpRow;
	LPDATABASE_VALUE	lpValue;
	WCHAR				wColumnName[16384], wColumnValue[16384];
	LONG				lColumnNameLength	= 0;
	LONG				lColumnValueLength	= 0;
	LONG				lResult;
	DWORD				dwBytesWritten;
	ULONG				lRowID, lRowIndex, lColumnID;
	BOOL				bError	= FALSE;
	BOOL				bReturn	= FALSE;

	/* commit collection changes and release locks - no locks for now */
	wColumnName[0]	= L' ';
	wColumnName[1]	= L'{';
	wColumnValue[0]	= L'{';
    
	hFile	= CreateFileW(GetDatabaseCollectionName(lpCollection[0]),
		GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE,
		0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
	if (hFile != INVALID_HANDLE_VALUE) {
		/* iterate all row ids */
		for (lRowID = 0;lRowID < GetDatabaseRowIDCount(lpDatabase) && ! bError;lRowID++) {
			/* iterate all rows */
			for (lRowIndex = 0;lRowIndex < GetCollectionRowCount(lpCollection[0], lRowID);lRowIndex++) {
				/* iterate all columns */
				lpRow	= GetCollectionRow(lpCollection[0], lRowID, lRowIndex);
				if (! lpRow) {
					continue;
				}

				lColumnValueLength	= 1;
				lColumnNameLength	= _snwprintf(wColumnName,
					sizeof(wColumnName) / sizeof(WCHAR) - 1, L"%s {", GetRowName(lpRow));
				if (lColumnNameLength > 0) {
					for (lColumnID = 0;lColumnID < GetRowColumnCount(lpRow);lColumnID++) {
						lpValue	= GetRowColumnValue(lpRow, lColumnID);
						if (! lpValue) {
							continue;
						}

						lResult	= EscapeStringCommas(GetRowColumnName(lpRow, lColumnID), 
							&wColumnName[lColumnNameLength], sizeof(wColumnName) / sizeof(WCHAR) - lColumnNameLength - 2);
						if (lResult <= 0) {
							/* failure */
							lColumnNameLength	= INFINITE;
							break;
						}
						lColumnNameLength	+= lResult;
						wColumnName[lColumnNameLength++]	= L',';

						lResult	= EscapeStringCommas(GetValueWString(lpValue),
							&wColumnValue[lColumnValueLength], sizeof(wColumnValue) / sizeof(WCHAR) - lColumnValueLength - 3);
						if (lResult < 0) {
							/* failure */
							lColumnValueLength	= INFINITE;
							break;
						}
						lColumnValueLength	+= lResult;
						wColumnName[lColumnValueLength++]	= L',';
					}

					if (lColumnValueLength != INFINITE && lColumnNameLength != INFINITE) {
						/* prepend buffers */
						wColumnName[lColumnNameLength - 1]		= L'}';
						wColumnName[lColumnNameLength++]		= L' ';
						wColumnValue[lColumnValueLength - 1]	= L'}';
						wColumnValue[lColumnValueLength++]		= L'\r';
						wColumnValue[lColumnValueLength++]		= L'\n';

						/* write to file */
						if (WriteFile(hFile, wColumnName, lColumnNameLength * sizeof(WCHAR), &dwBytesWritten, 0)
							&& WriteFile(hFile, wColumnValue, lColumnValueLength * sizeof(WCHAR), &dwBytesWritten, 0)) {
							/* success */
							continue;
						}
					}
				} else {
					/* out of buffer space */
					lColumnNameLength	= INFINITE;
				}
				bError	= TRUE;
				break;
			}
		}
		CloseHandle(hFile);

		if (! bError) {
			bReturn	= TRUE;
		}
	}
	return bReturn;
}


BOOL CancelCollectionChanges(LPDATABASE lpDatabase, LPDATABASE_COLLECTION *lpCollection)
{
	/* cancel collection changes and release locks - does nothing for now */
	return TRUE;
}


BOOL QueryCollection(LPDATABASE lpDatabase, LPDATABASE_COLLECTION lpCollection)
{
	LPDATABASE_VALUE	lpValue;
	HANDLE				hFile;
	LPWSTR				*wszColumnName, *wszColumnValue;
	PWCHAR				pLine, pBuffer, pEnd, pCurrent, pOpeningBrace[2], pClosingBrace, pWordEnd;
	ULONG				lBufferLength, lRowID, lRowIndex, lColumnID, lColumnNameCount, lColumnValueCount, lWord, lWordCount;
	BOOL				bReturn	= FALSE;

	/* query collection */
	hFile	= CreateFileW(GetDatabaseCollectionName(lpCollection[0]),
		GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE,
		0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
	if (hFile != INVALID_HANDLE_VALUE) {
		lBufferLength	= GetFileSize(hFile, 0);
		if (lBufferLength != INVALID_FILE_SIZE || GetLastError() == NO_ERROR) {
			pBuffer	= (WCHAR *)Allocate("Collection read buffer", lBufferLength + sizeof(WCHAR));
			if (pBuffer != 0) {
				if (ReadFile(hFile, pBuffer, lBufferLength, &lBufferLength, 0)) {
					lBufferLength	= (lBufferLength / 2) + 1;
					pBuffer[lBufferLength - 1]	= L'\n';

					/* seek entries */
					for (pLine = pBuffer;(pCurrent = wmemchr(pLine, L'\n', pEnd - pCurrent)) != 0;pLine = &pCurrent[1]) {
						pCurrent[(pLine > pCurrent && pCurrent[-1] == L'\r' ? -1 : 0]	= L'\0';

						pOpeningBrace[0]	= wmemchr(pLine, L'{', pCurrent - pLine);
						if (! pOpeningBrace[0]) {
							/* no opening brace */
							continue;
						}
						pClosingBrace[0]	= wmemchr(&pOpeningBrace[0][1], L'}', pCurrent - &pOpeningBrace[0][1]);
						if (! pClosingBrace[0]) {
							/* no closing brace */
							continue;
						}
						pOpeningBrace[1]	= wmemchr(&pClosingBrace[0][1], L'{', pCurrent - &pClosingBrace[0][1]);
						if (! pOpeningBrace[1]) {
							/* no opening brace */
							continue;
						}
						pClosingBrace[1]	= wmemchr(&pOpeningBrace[1][1], L'}', pCurrent - &pOpeningBrace[1][1]);
						if (! pClosingBrace) {
							/* no closign brace */
							continue;
						}
						pClosingBrace[0][0]	= '\0';
						pClosingBrace[1][0]	= '\0';

						/* remove heading and tailing spaces */
						for (pWordEnd = pOpeningBrace[0];pWordEnd > pLine && iswspace(pWordEnd[-1]);--pWordEnd);
						pWordEnd[0]	= L'\0';
						for (;pLine < pWordEnd && iswspace(pLine[0]);++pLine);

						for (lRowID = 0;lRowID < GetDatabaseRowIDCount(lpDatabase);lRowID++) {
							if (! wcsicmp(GetDatabaseRowName(lpDatabase, lRowID), pLine)) {
								/* create row and get known columns */
								lRowIndex	= CreateCollectionRow(lpCollection[0], lRowID);
								if (lRowIndex == INFINITE) {
									/* error could not create row */
									break;
								}

								/* tokenize strings */
								wszColumnName	= TokenizeCommaSeperatedString(&pOpeningBrace[0][1], &lColumnNameCount);
								if (wszColumnName != 0) {
									wszColumnValue	= TokenizeCommaSeperatedString(&pOpeningBrace[1][1], &lColumnValueCount);
									if (wszColumnValue != 0) {
										/* get known columns */
										lWordCount	= min(lColumnNameCount, lColumnValueCount);
										for (lColumnID = 0;lColumnID < GetDatabaseRowColumnCount(lpDatabase, lRowID);++lColumnID) {
											for (lWord = 0;lWord < lWordCount;lWord++) {
												if (! _wcsicmp(GetDatabaseRowColumnName(lpDatabase, lRowID, lColumnID), wszColumnName[n])) {
													/* create value */
													lpValue	= CreateWStringValue(wszColumnValue[n]);
													if (lpValue != 0) {
														if (! SetCollectionRowColumnValue(lpCollection, lRowID, lRowIndex, lColumnID, lpValue)) {
															FreeValue(lpValue);
														}
													}
													break;
												}
											}
										}
										Free(wszColumnValue);
									}
		                            Free(wszColumnName);
								}
								break;
							}
						}
					}
				}
				Free(pBuffer);
			}
		}
		CloseHandle(hFile);
	}
	return bReturn;
}


BOOL DeleteCollection(LPDATABASE lpDatabase, LPDATABASE_COLLECTION lpCollection)
{
	/* delete collection */
	return DeleteFileW(GetDatabaseCollectionName(lpCollection));
}

BOOL CreateCollection(LPDATABASE lpDatabase, LPWSTR wszCollectionName)
{
	HANDLE	hFile;
	BOOL	bReturn	= FALSE;

	/* create collection */
	hFile	= CreateFileW(wszCollectionName,
		GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE,
		0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0;
	if (hFile != INVALID_HANDLE_VALUE) {
		bReturn	= TRUE;
		CloseHandle(hFile);
	}
	return bReturn;
}

BOOL Shutdown(LPDATABASE lpDatabase)
{
	/* module shutdown */
	return TRUE;
}
darkone is offline   Reply With Quote