|
|
/*
* @doc INTERNAL * * @module RTFLOG.CPP - RichEdit RTF log * * Contains the code for the RTFLog class which can be used * to log the number of times RTF tags are read by the RTF reader * for use in coverage testing. TODO: Implement RTF tag logging for the Mac * * Authors:<nl> * Created for RichEdit 2.0: Brad Olenick * * Copyright (c) 1995-2000, Microsoft Corporation. All rights reserved. */
#include "_common.h"
#include "_rtflog.h"
#include "tokens.h"
extern INT cKeywords; extern const KEYWORD rgKeyword[];
#if defined(DEBUG) && !defined(NOFULLDEBUG)
/*
* CRTFRead::TestParserCoverage() * * @mfunc * A debug routine used to test the coverage of HandleToken. The routine * puts the routine into a debug mode and then determines: * * 1. Dead tokens - (T & !S & !P) * Here, token: * a) is defined in token.h (T) * b) does not have a corresponding keyword (not scanned) (!S) * c) is not processed by HandleToken (!P) * 2. Tokens that are parsed but not scanned - (T & !S & P) * Here, token: * a) is defined in token.h (T) * b) does not have a corresponding keyword (not scanned) (!S} * c) is processed by HandleToken (P) * 3. Tokens that are scanned but not parsed - (T & S & !P) * Here, token: * a) is defined in token.h (T) * b) does have a corresponding keyword (is scanned) (S) * c) is not processed by HandleToken (!P) */ void CRTFRead::TestParserCoverage() { int i; char *rgpszKeyword[tokenMax - tokenMin]; BOOL rgfParsed[tokenMax - tokenMin]; char szBuf[256];
// Put HandleToken in debug mode
_fTestingParserCoverage = TRUE;
// Gather info about tokens/keywords
for(i = 0; i < tokenMax - tokenMin; i++) { _token = (TOKEN)(i + tokenMin); rgpszKeyword[i] = PszKeywordFromToken(_token); rgfParsed[i] = HandleToken() == ecNoError; }
// Reset HandleToken to non-debug mode
_fTestingParserCoverage = FALSE;
// Should coverage check include those we know will fail test, but
// which we've examined and know why they fail?
BOOL fExcuseCheckedToks = TRUE;
if(GetProfileIntA("RICHEDIT DEBUG", "RTFCOVERAGESTRICT", 0)) fExcuseCheckedToks = FALSE;
// (T & !S & !P) (1. above)
for(i = 0; i < tokenMax - tokenMin; i++) { if(rgpszKeyword[i] || rgfParsed[i]) continue;
TOKEN tok = (TOKEN)(i + tokenMin);
// Token does not correspond to a keyword, but still may be scanned
// check list of individual symbols which are scanned
if(FTokIsSymbol(tok)) continue;
// Check list of tokens which have been checked and fail
// the sanity check for some known reason (see FTokFailsCoverageTest def'n)
if(fExcuseCheckedToks && FTokFailsCoverageTest(tok)) continue;
sprintf(szBuf, "CRTFRead::TestParserCoverage(): Token neither scanned nor parsed - token = %d", tok); AssertSz(0, szBuf); }
// (T & !S & P) (2. above)
for(i = 0; i < tokenMax - tokenMin; i++) { if(rgpszKeyword[i] || !rgfParsed[i]) continue;
TOKEN tok = (TOKEN)(i + tokenMin);
// Token does not correspond to a keyword, but still may be scanned
// check list of individual symbols which are scanned
if(FTokIsSymbol(tok)) continue;
// Check list of tokens which have been checked and fail
// the sanity check for some known reason (see FTokFailsCoverageTest def'n)
if(fExcuseCheckedToks && FTokFailsCoverageTest(tok)) continue;
sprintf(szBuf, "CRTFRead::TestParserCoverage(): Token parsed but not scanned - token = %d", tok); AssertSz(0, szBuf); }
// (T & S & !P) (3. above)
for(i = 0; i < tokenMax - tokenMin; i++) { if(!rgpszKeyword[i] || rgfParsed[i]) continue;
TOKEN tok = (TOKEN)(i + tokenMin);
// Check list of tokens which have been checked and fail
// the sanity check for some known reason (see FTokFailsCoverageTest def'n)
if(fExcuseCheckedToks && FTokFailsCoverageTest(tok)) continue;
sprintf(szBuf, "CRTFRead::TestParserCoverage(): Token scanned but not parsed - token = %d, tag = \\%s", tok, rgpszKeyword[i]); AssertSz(0, szBuf); } }
/*
* CRTFRead::PszKeywordFromToken() * * @mfunc * Searches the array of keywords and returns the keyword * string corresponding to the token supplied * * @rdesc * returns a pointer to the keyword string if one exists * and NULL otherwise */ CHAR *CRTFRead::PszKeywordFromToken(TOKEN token) { for(int i = 0; i < cKeywords; i++) { if(rgKeyword[i].token == token) return rgKeyword[i].szKeyword; } return NULL; }
/*
* CRTFRead::FTokIsSymbol(TOKEN tok) * * @mfunc * Returns a BOOL indicating whether the token, tok, corresponds to an RTF symbol * (that is, one of a list of single characters that are scanned in the * RTF reader) * * @rdesc * BOOL - indicates whether the token corresponds to an RTF symbol */ BOOL CRTFRead::FTokIsSymbol(TOKEN tok) { const BYTE *pbSymbol = NULL;
extern const BYTE szSymbolKeywords[]; extern const TOKEN tokenSymbol[];
// check list of individual symbols which are scanned
for(pbSymbol = szSymbolKeywords; *pbSymbol; pbSymbol++) { if(tokenSymbol[pbSymbol - szSymbolKeywords] == tok) return TRUE; } return FALSE; }
/*
* CRTFRead::FTokFailsCoverageTest(TOKEN tok) * * @mfunc * Returns a BOOL indicating whether the token, tok, is known to fail the * RTF parser coverage test. These tokens are those that have been checked * and either: * 1) have been implemented correctly, but just elude the coverage test * 2) have yet to be implemented, and have been recognized as such * * @rdesc * BOOL - indicates whether the token has been checked and fails the * the parser coverage test for some known reason */ BOOL CRTFRead::FTokFailsCoverageTest(TOKEN tok) { switch(tok) { // (T & !S & !P) (1. in TestParserCoverage)
// these really aren't tokens per se, but signal ending conditions for the parse
case tokenError: case tokenEOF:
// (T & !S & P) (2. in TestParserCoverage)
// emitted by scanner, but don't correspond to recognized RTF keyword
case tokenUnknownKeyword: case tokenText: case tokenASCIIText:
// recognized directly (before the scanner is called)
case tokenStartGroup: case tokenEndGroup:
// recognized using context information (before the scanner is called)
case tokenObjectDataValue: case tokenPictureDataValue:
// (T & S & !P) (3. in TestParserCoverage)
// None
return TRUE; }
return FALSE; } #endif // DEBUG
/*
* CRTFLog::CRTFLog() * * @mfunc * Constructor - * 1. Opens a file mapping to log hit counts, creating * the backing file if neccessary * 2. Map a view of the file mapping into memory * 3. Register a windows message for change notifications * */ CRTFLog::CRTFLog() : _rgdwHits(NULL), _hfm(NULL), _hfile(NULL) { #ifndef NOFULLDEBUG
const char cstrMappingName[] = "RTFLOG"; const char cstrWM[] = "RTFLOGWM"; const int cbMappingSize = sizeof(ELEMENT) * ISize();
BOOL fNewFile = FALSE;
// Check for existing file mapping
if(!(_hfm = OpenFileMappingA(FILE_MAP_ALL_ACCESS, TRUE, cstrMappingName))) { // No existing file mapping
// Get the file with which to create the file mapping
// first, attempt to open an existing file
if(!(_hfile = CreateFileA(LpcstrLogFilename(), GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL))) { // No existing file, attempt to create new
if(!(_hfile = CreateFileA(LpcstrLogFilename(), GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL))) { return; } fNewFile = TRUE; }
_hfm = CreateFileMappingA(_hfile, NULL, PAGE_READWRITE, 0, cbMappingSize, cstrMappingName); if(!_hfm) return; }
LPVOID lpv = MapViewOfFile(_hfm, FILE_MAP_ALL_ACCESS, 0, 0, cbMappingSize); if(!lpv) return;
// Register windows message for change notifications
SideAssert(_uMsg = RegisterWindowMessageA(cstrWM));
// Memory-mapped file is now mapped to _rgdwHits
_rgdwHits = (PELEMENT)lpv;
// Zero the memory-mapped file if we created it new
// (Win95 gives us a new file w/ garbage in it for some reason)
if(fNewFile) Reset(); #endif
}
/*
* CRTFLog::Reset() * * @mfunc * Resets the hitcount of each element in the log to 0 * */ void CRTFLog::Reset() { if(!FInit()) return;
for(INDEX i = 0; i < ISize(); i++) (*this)[i] = 0;
// notify clients of change
ChangeNotifyAll(); }
/*
* CRTFLog::UGetWindowMsg * * @mdesc * Returns the window message id used for change notifications * * @rdesc * UINT window message id * * @devnote * This should be inline, but the AssertSz macro doesn't compile * properly on the Mac if its placed in a header file * */ UINT CRTFLog::UGetWindowMsg() const { AssertSz(FInit(), "CRTFLog::UGetWindowMsg(): CRTFLog not initialized properly");
return _uMsg; }
/*
* CRTFLog::operator[] * * @mdesc * Returns reference to element i of RTF log (l-value) * * @rdesc * ELEMENT & reference to element i of log * * @devnote * This should be inline, but the AssertSz macro doesn't compile * properly on the Mac if its placed in a header file * */ CRTFLog::ELEMENT &CRTFLog::operator[](INDEX i) { AssertSz(i < ISize(), "CRTFLog::operator[]: index out of range"); AssertSz(FInit(), "CRTFLog::operator[]: CRTFLog not initialized properly");
return _rgdwHits[i]; }
/*
* CRTFLog::operator[] * * @mdesc * Returns reference to element i of RTF log (r-value) * * @rdesc * const ELEMENT & reference to element i of log * * @devnote * This should be inline, but the AssertSz macro doesn't compile * properly on the Mac if its placed in a header file * */ const CRTFLog::ELEMENT &CRTFLog::operator[](INDEX i) const { AssertSz(i < ISize(), "CRTFLog::operator[]: index out of range"); AssertSz(FInit(), "CRTFLog::operator[]: CRTFLog not initialized properly");
return _rgdwHits[i]; }
/*
* CRTFLog::LpcstrLogFilename() * * @mfunc * Returns name of file to be used for log * * @rdesc * LPCSTR pointer to static buffer containing file name */ LPCSTR CRTFLog::LpcstrLogFilename() const { static char szBuf[MAX_PATH] = ""; #ifndef NOFULLDEBUG
const char cstrLogFilename[] = "RTFLOG"; if(!szBuf[0]) { DWORD cchLength; char szBuf2[MAX_PATH];
SideAssert(cchLength = GetTempPathA(MAX_PATH, szBuf2));
// append trailing backslash if neccessary
if(szBuf2[cchLength - 1] != '\\') { szBuf2[cchLength] = '\\'; szBuf2[cchLength + 1] = 0; }
wsprintfA(szBuf, "%s%s", szBuf2, cstrLogFilename); } #endif
return szBuf; }
/*
* CRTFLog::IIndexOfKeyword(LPCSTR lpcstrKeyword, PINDEX piIndex) * * @mfunc * Returns the index of the log element which corresponds to * the RTF keyword, lpcstrKeyword * * @rdesc * BOOL flag indicating whether index was found */ BOOL CRTFLog::IIndexOfKeyword(LPCSTR lpcstrKeyword, PINDEX piIndex) const { INDEX i;
for(i = 0; i < ISize(); i++) { if(strcmp(lpcstrKeyword, rgKeyword[i].szKeyword) == 0) break; }
if(i == ISize()) return FALSE;
if(piIndex) *piIndex = i;
return TRUE; }
/*
* CRTFLog::IIndexOfToken(TOKEN token, PINDEX piIndex) * * @mfunc * Returns the index of the log element which corresponds to * the RTF token, token * * @rdesc * BOOL flag indicating whether index was found */ BOOL CRTFLog::IIndexOfToken(TOKEN token, PINDEX piIndex) const { INDEX i;
for(i = 0; i < ISize(); i++) { if(token == rgKeyword[i].token) break; }
if(i == ISize()) return FALSE;
if(piIndex) *piIndex = i;
return TRUE; }
|