Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1068 lines
30 KiB

/*
* Private headers
*/
#ifndef STRICT
#define STRICT
#endif
#ifndef WIN32_LEAN_AND_MEAN /* build.exe will define it for us on NT */
#define WIN32_LEAN_AND_MEAN
#endif
#undef WINVER /* build process defines this */
#define WINVER 0x0400 /* Windows 95 compatible */
#define _WIN32_WINDOWS 0x0400 /* Windows 95 compatible */
#include <windows.h> /* Everybody's favourite */
#include <commctrl.h>
#ifndef RC_INVOKED
#include <windowsx.h> /* Message crackers */
#include <shlwapi.h>
#include <shellapi.h>
#endif
/*****************************************************************************
*
* Resources
*
*****************************************************************************/
/*
* Icons
*/
#define IDI_SDV 0x0001
/*
* Bitmaps
*/
#define IDB_PLUS 0x0001
#define IDB_IMAGES 0x0002
/*
* Strings
*/
#define IDS_TITLE 0x0001
#define IDS_IE4 0x0002
#define IDS_SD_EXEC_ERR 0x0003
#define IDS_DEFAULT_BUGPAGE 0x0004
#define IDS_VIEWBUG_FORMAT 0x0005
#define IDS_VIEWBUG_NONE 0x0006
#define IDS_COL_REV 0x0100
#define IDS_COL_CHANGE 0x0101
#define IDS_COL_OP 0x0102
#define IDS_COL_DATE 0x0103
#define IDS_COL_DEV 0x0104
#define IDS_COL_CHURN 0x0105
#define IDS_COL_COMMENT 0x0106
/*
* Menus
*/
#define IDM_CHANGES 1
#define IDM_CHANGES_POPUP 2
#define IDM_DESCRIBE 3
#define IDM_DESCRIBE_POPUP 4
#define IDM_FILELOG 5
#define IDM_FILELOG_POPUP 6
#define IDM_OPENED 7
#define IDM_OPENED_POPUP 8
#define IDM_EXIT 100
#define IDM_EXITALL 101
#define IDM_COPY 102
#define IDM_COPYALL 103
#define IDM_VIEWDESC 104
#define IDM_VIEWFILEDIFF 105
#define IDM_VIEWWINDIFF 106
#define IDM_VIEWBUG 107
#define IDM_VIEWFILELOG 108
#define IDM_HELP 200
/*
* Accelerators
*/
#define IDA_CHANGES 1
#define IDA_DESCRIBE 2
#define IDA_FILELOG 3
#define IDA_OPENED 4
/*****************************************************************************
*
* Assorted goo
*
*****************************************************************************/
#ifndef RC_INVOKED
extern HINSTANCE g_hinst;
extern HCURSOR g_hcurWait;
extern HCURSOR g_hcurArrow;
extern HCURSOR g_hcurAppStarting;
extern LONG g_lThreads;
extern TCHAR g_szTitle[MAX_PATH];
extern UINT g_wShowWindow;
DWORD EndThreadTask(DWORD dwExitCode);
#ifndef ARRAYSIZE
#define ARRAYSIZE(a) (sizeof(a)/sizeof(a[0]))
#endif
#ifndef NO_VTABLE
#define NO_VTABLE __declspec(novtable)
#endif
/*
* Because C++ syntax is so ugly.
*/
#define SAFECAST(T, p) static_cast<T>(p)
#define RECAST(T, p) reinterpret_cast<T>(p)
#define CCAST(T, p) const_cast<T>(p)
/*****************************************************************************
*
* Utility goo
*
*****************************************************************************/
class String;
int ListView_GetCurSel(HWND hwnd);
void ListView_SetCurSel(HWND hwnd, int iIndex);
int ListView_GetSubItemText(HWND hwnd, int iItem, int iSubItem, LPTSTR pszBuf, int cch);
#undef ListView_GetItemText
#define ListView_GetItemText(hwnd, iItem, pszBuf, cch) \
ListView_GetSubItemText(hwnd, iItem, 0, pszBuf, cch)
void ChangeTabsToSpaces(LPTSTR psz);
void PremungeFilespec(LPTSTR psz);
void PostmungeFilespec(LPTSTR psz);
BOOL ContainsWildcards(LPCTSTR psz);
enum MAPTOX {
MAPTOX_DEPOT, // //depot/path
MAPTOX_CLIENT, // //CLIENT/path
MAPTOX_LOCAL, // C:\src\path
};
BOOL MapToXPath(LPCTSTR pszSD, String& strOut, MAPTOX X);
inline BOOL MapToFullDepotPath(LPCTSTR pszSD, String& strOut)
{ return MapToXPath(pszSD, strOut, MAPTOX_DEPOT); }
inline BOOL MapToClientPath(LPCTSTR pszSD, String& strOut)
{ return MapToXPath(pszSD, strOut, MAPTOX_CLIENT); }
BOOL MapToLocalPath(LPCTSTR pszSD, String& strOut);
void Help(HWND hwnd, LPCTSTR pszAnchor);
BOOL SpawnProcess(LPTSTR pszCommand);
void WindiffChangelist(int iChange);
void WindiffOneChange(LPTSTR pszPath);
int ParseBugNumber(LPCTSTR psz);
int ParseBugNumberFromSubItem(HWND hwnd, int iItem, int iSubItem);
void AdjustBugMenu(HMENU hmenu, int iBug, BOOL fContextMenu);
void OpenBugWindow(HWND hwnd, int iBug);
void JiggleMouse();
HMENU LoadPopupMenu(LPCTSTR pszMenu);
void MakeMenuPretty(HMENU hmenu);
void EnableDisableOrRemoveMenuItem(HMENU hmenu, UINT id, BOOL fEnable, BOOL fDelete);
void SetClipboardText(HWND hwnd, LPCTSTR psz);
// SCHAR is the opposite of TCHAR
#ifdef UNICODE
typedef CHAR SCHAR;
#else
typedef WCHAR SCHAR;
#endif
typedef SCHAR *LPSSTR;
typedef const SCHAR *LPCSSTR;
/*****************************************************************************
*
* Change types
*
*****************************************************************************/
enum {
OP_UNKNOWN,
OP_EDIT,
OP_DELETE,
OP_ADD,
OP_INTEGRATE,
OP_MERGE,
OP_BRANCH,
OP_COPY,
OP_IGNORED,
OP_MAX,
};
extern struct LogEntryImageMap {
LPCTSTR _pszOp;
int _iImage;
} c_rgleim[];
int ParseOp(LPCTSTR psz);
/*****************************************************************************
*
* Assertion goo
*
*****************************************************************************/
#ifdef DEBUG
void AssertFailed(char *psz, char *pszFile, int iLine);
#define ASSERT(f) ((f) || (AssertFailed(#f, __FILE__, __LINE__), 0))
#else
#define ASSERT sizeof
#endif
#define COMPILETIME_ASSERT(f) switch (0) case 0: case f:
/*****************************************************************************
*
* Downlevel OS support (is this still needed?)
*
*****************************************************************************/
#undef SUPPORT_DOWNLEVEL
#ifdef SUPPORT_DOWNLEVEL
typedef BOOL (WINAPI *QUEUEUSERWORKITEM)(LPTHREAD_START_ROUTINE, LPVOID, ULONG);
typedef BOOL (WINAPI *ALLOWSETFOREGROUNDWINDOW)(DWORD);
extern QUEUEUSERWORKITEM _QueueUserWorkItem;
extern ALLOWSETFOREGROUNDWINDOW _AllowSetForegroundWindow;
#else
#define _QueueUserWorkItem QueueUserWorkItem
#define _AllowSetForegroundWindow AllowSetForegroundWindow
#endif
/*****************************************************************************
*
* Ctype
*
*****************************************************************************/
#define C_NONE 0x00
#define C_SPACE 0x01
#define C_DIGIT 0x02
#define C_ALPHA 0x04
#define C_DASH 0x08
#define C_BRNCH 0x10
#define B_DEFAULT C_NONE // Characters above 128 are this
extern const BYTE c_rgbCtype[128];
inline BOOL _InOrder(UINT tch1, UINT tch2, UINT tch3)
{
return tch2 - tch1 <= tch3 - tch1;
}
inline BOOL _Ctype(TCHAR tch, BYTE fl)
{
UINT ui = (UINT)tch;
BYTE b;
if (ui < ARRAYSIZE(c_rgbCtype)) {
b = c_rgbCtype[ui];
} else {
b = B_DEFAULT;
}
return b & fl;
}
inline BOOL IsSpace(TCHAR tch)
{
return _Ctype(tch, C_SPACE);
}
inline BOOL IsDigit(TCHAR tch)
{
return _Ctype(tch, C_DIGIT);
}
inline BOOL IsNZDigit(TCHAR tch)
{
return _InOrder(TEXT('1'), tch, TEXT('9'));
}
inline BOOL IsAlpha(TCHAR tch)
{
return _Ctype(tch, C_ALPHA);
}
inline BOOL IsAlias(TCHAR tch)
{
return _Ctype(tch, C_DASH | C_DIGIT | C_ALPHA);
}
inline BOOL IsBranch(TCHAR tch)
{
return _Ctype(tch, C_DASH | C_DIGIT | C_ALPHA | C_BRNCH);
}
inline BOOL _IsPrint(TCHAR tch)
{
return _InOrder(TEXT(' '), tch, TEXT('~'));
}
#define _IsWord(ch) ((UINT)(ch) > TEXT(' '))
/*****************************************************************************
*
* Commands
*
*****************************************************************************/
extern DWORD CALLBACK CChanges_ThreadProc(LPVOID lpParameter);
extern DWORD CALLBACK CDescribe_ThreadProc(LPVOID lpParameter);
extern DWORD CALLBACK CFileLog_ThreadProc(LPVOID lpParameter);
extern DWORD CALLBACK CFileOut_ThreadProc(LPVOID lpParameter);
extern DWORD CALLBACK COpened_ThreadProc(LPVOID lpParameter);
BOOL LaunchThreadTask(LPTHREAD_START_ROUTINE pfn, LPCTSTR pszArgs);
/*****************************************************************************
*
* String, _String, OutputStringBuffer
*
* An extremely lame low-performance string class
* Be careful what you do with it since you can't do much.
*
* _String is the base class that does the heavy lifting and shunts long
* strings into the heap.
*
* String collects strings into a private buffer (which can overflow into
* the heap).
*
* OutputStringBuffer collects strings into the buffer provided
* (which can overflow into the heap). On destruction, copies the result
* if necessary back to the buffer provided.
*
*****************************************************************************/
class _String
{
public:
explicit _String(LPTSTR pszBufOrig, UINT cchBufOrig);
~_String();
void Reset();
operator LPTSTR() const { return _pszBuf; }
LPTSTR Buffer() const { return _pszBuf; }
int BufferLength() const { return _cchBuf; }
_String& operator<<(LPCTSTR psz) { Append(psz); return *this; }
_String& operator<<(const _String& str) { Append(str); return *this; }
_String& operator<<(int i);
_String& operator<<(TCHAR tch);
_String& operator=(LPCTSTR psz) { Reset(); Append(psz); return *this; }
int Length() const { return _cchLen; }
BOOL Append(LPCTSTR psz);
BOOL Append(const _String& str) { return Append(str, str.Length()); }
BOOL Append(LPCTSTR psz, int cchLen);
BOOL Grow(int cchLen) { return Append(NULL, cchLen); }
BOOL Ensure(int cchLen);
void Trim(int cchTrim = 1) { _pszBuf[_cchLen -= cchTrim] = TEXT('\0'); }
void SetLength(int cchLen) { ASSERT(_cchLen < _cchBuf); _cchLen = cchLen; }
void Chomp();
protected:
LPTSTR OriginalBuffer() const { return _pszBufOrig; }
private:
// Disallow the default copy constructor and assignment operator.
// Since our class has pointers, a block copy is never correct.
_String(const _String&); // never defined
_String& operator=(const _String&); // never defined
LPTSTR _pszBuf;
int _cchLen;
int _cchBuf;
LPTSTR _pszBufOrig;
};
class String : public _String
{
public:
explicit String() : _String(_szBuf, ARRAYSIZE(_szBuf)) { }
explicit String(LPCTSTR psz) : _String(_szBuf, ARRAYSIZE(_szBuf)) { Append(psz); }
String& operator=(LPCTSTR psz) { _String::operator=(psz); return *this; }
private:
/* Almost all strings are smaller than this */
TCHAR _szBuf[MAX_PATH];
};
class OutputStringBuffer : public _String
{
public:
OutputStringBuffer(LPTSTR pszBuf, UINT cchBuf)
: _String(pszBuf, cchBuf)
, _cchBufOrig(cchBuf) { }
~OutputStringBuffer();
private:
int _cchBufOrig;
};
/*****************************************************************************
*
* Custom output formats for "str << blah"
*
*****************************************************************************/
class _StringFormat {
public:
operator LPCTSTR() const { return _pszDepotPath; }
_StringFormat(LPCTSTR pszDepotPath) : _pszDepotPath(pszDepotPath) { }
protected:
LPCTSTR _pszDepotPath;
};
#define MakeStringFormat(T) \
class T : public _StringFormat { \
public: \
T(LPCTSTR pszDepotPath) : _StringFormat(pszDepotPath) { } \
}; \
_String& operator<<(_String& str, T t); \
MakeStringFormat(QuoteSpaces)
MakeStringFormat(BranchOf)
MakeStringFormat(FilenameOf)
MakeStringFormat(ResolveBranchAndQuoteSpaces)
class StringResource {
public:
operator UINT() const { return _ids; }
StringResource(UINT ids) : _ids(ids) { }
protected:
UINT _ids;
};
_String& operator<<(_String& str, StringResource sr);
#define StringBeginsWith(psz, sz) (StrCmpN(psz, sz, ARRAYSIZE(sz) - 1) == 0)
/*****************************************************************************
*
* StringCache is a class that babysits a string pointer.
*
* _StringCache is the version that requires explicit
* construction/destruction. It is safe to use in global structures.
*
*****************************************************************************/
struct _StringCache {
public:
_StringCache& operator=(LPCTSTR psz);
BOOL IsEmpty() const { return _psz == NULL; }
operator LPTSTR() const { return Value(); }
LPTSTR Value() const { return IsEmpty() ? TEXT("") : _psz; }
public:
LPTSTR _psz;
};
class StringCache : public _StringCache
{
public:
StringCache() { _psz = NULL; }
StringCache(LPCTSTR psz) { _psz = NULL; *this = psz; }
~StringCache() { *this = NULL; }
StringCache& operator=(LPCTSTR psz)
{ *SAFECAST(_StringCache*,this) = psz; return *this; }
};
/*
* match.cpp - Highly-specialized depot path matching class
*/
class Match {
public:
Match(LPCTSTR pszPattern);
~Match() { delete [] _pszzPats; }
BOOL Matches(LPCTSTR pszPath);
private:
void _AddPattern(LPTSTR pszPat, String& strPats);
BOOL _Matches(LPCTSTR pszPat, LPCTSTR pszPath);
private:
LPTSTR _pszzPats;
LPTSTR _pszEnd;
};
/*
* pipe.cpp
*/
class ChildProcess
{
public:
explicit ChildProcess() { Construct(); }
explicit ChildProcess(LPCTSTR pszCommand) { Construct(); Start(pszCommand); }
void Start(LPCTSTR pszCommand);
~ChildProcess() { Stop(); }
BOOL IsRunning() const { return _dwPid; }
HANDLE Handle() const { return _hRead; }
void Kill();
void Stop();
private:
void Construct()
{
_hProcess = NULL;
_hRead = NULL;
_dwPid = 0;
}
private:
HANDLE _hRead;
HANDLE _hProcess;
DWORD _dwPid;
};
class SDChildProcess : public ChildProcess
{
public:
explicit SDChildProcess(LPCTSTR pszCommand);
};
/*
* buffer.cpp
*/
class IOBuffer
{
public:
IOBuffer(HANDLE hRead) { Init(hRead); }
void Init(HANDLE hRead) { _hRead = hRead; _cchBufUsed = 0; }
BOOL NextLine(String &);
private:
enum {
_cchBuf = MAX_PATH,
};
HANDLE _hRead;
TCHAR _rgchBuf[_cchBuf];
int _cchBufUsed; /* Number of bytes already in buffer */
};
/*****************************************************************************
*
* LVInfoTip - lvframe.cpp
*
* Special hack class to support extra-long infotips in listview.
*
*****************************************************************************/
class LVInfoTip
{
public:
void Attach(HWND hwnd);
~LVInfoTip() { FreeLastTipAlt(); }
void SetInfoTip(NMLVGETINFOTIP *pgit, LPCTSTR pszTip);
private:
void FreeLastTipAlt();
BOOL ThunkLastTip();
static LRESULT SubclassWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
static LPCTSTR GetSubclassProperty() { return TEXT("LVInfoTip"); }
private:
WNDPROC _wndprocPrev;
BOOL _fGotInfoTip;
LPCTSTR _pszLastTip;
LPSSTR _pszLastTipAlt;
};
/*****************************************************************************
*
* TreeList - treelist.cpp
*
* A tree-like listview.
*
*****************************************************************************/
/*
* We maintain our own tree structure and add/delete items in the
* listview as necessary as tree nodes are expanded/collapsed.
*/
#define PTI_ONDEMAND RECAST(TreeItem*, -1)
#define PTI_APPEND RECAST(TreeItem*, -1)
class TreeItem {
public:
TreeItem * Parent() const { return _ptiParent; }
TreeItem * NextSibling() const { return _ptiNext; }
TreeItem * FirstChild() const { return _ptiChild; }
TreeItem * NextVisible();
BOOL IsExpanded() const { return _cVisKids > 0; }
BOOL IsExpandable() const { return _ptiChild != NULL; }
BOOL IsVisible();
BOOL IsVisibleOrRoot();
void SetExpandable() { SetFirstChild(PTI_ONDEMAND); }
void SetNotExpandable() { SetFirstChild(NULL); }
private:
friend class Tree;
BOOL IsSentinel() const { return this == NULL || this == PTI_ONDEMAND; }
void SetFirstChild(TreeItem *pti) { ASSERT(_ptiChild->IsSentinel()); _ptiChild = pti; }
private:
TreeItem * _ptiParent;
TreeItem * _ptiNext;
TreeItem * _ptiChild;
int _iDepth;
int _iVisIndex;
int _cVisKids;
};
#define TLN_GETDISPINFO 100 // Get pszText/cchTextMax given pti/iSubItem
#define TLN_FILLCHILDREN 101 // Fill children of pti
#define TLN_ITEMACTIVATE 102 // Default action on pti
#define TLN_GETINFOTIP 103 // Get pszText/cchTextMax given pti
#define TLN_DELETEITEM 104 // Destruct the node
#define TLN_GETCONTEXTMENU 105 // Display a context menu
struct NMTREELIST {
NMHDR hdr;
TreeItem *pti;
int iSubItem;
LPTSTR pszText;
int cchTextMax; // Doubles as state
};
class Tree {
public:
Tree(TreeItem *ptiRoot);
~Tree();
TreeItem* GetRoot() { return _ptiRoot; }
BOOL Insert(TreeItem *pti, TreeItem *ptiParent, TreeItem *ptiAfter);
void SetHWND(HWND hwnd);
int Expand(TreeItem *pti);
int Collapse(TreeItem *pti);
int ToggleExpand(TreeItem *pti);
void RedrawItem(TreeItem *pti);
TreeItem *GetCurSel();
void SetCurSel(TreeItem *pti);
HIMAGELIST SetImageList(HIMAGELIST himl);
public: //$$// make these protected someday
LRESULT OnGetDispInfo(NMLVDISPINFO *plvd);
LRESULT OnCacheHint(NMLVCACHEHINT *phint);
LRESULT OnItemActivate(int iItem);
LRESULT OnKeyDown(NMLVKEYDOWN *pkd);
LRESULT OnClick(NMITEMACTIVATE *pia);
LRESULT OnGetInfoTip(NMLVGETINFOTIP *pgit);
LRESULT OnGetContextMenu(int iItem);
LRESULT OnCopyToClipboard(int iMin, int iMax);
private:
void Recalc(TreeItem *pti);
void UpdateCache(TreeItem *pti, int iItem);
LRESULT SendNotify(int code, NMHDR *pnm);
TreeItem* IndexToItem(int iItem);
int InsertListviewItem(int iItem);
void UpdateVisibleCounts(TreeItem *pti, int cDelta);
void DeleteNode(TreeItem *pti);
void SendDeleteNotify(TreeItem *pti);
private:
HWND _hwnd;
TreeItem* _ptiRoot;
int _iHint;
TreeItem* _ptiHint;
};
/*****************************************************************************
*
* FrameWindow - window.cpp
*
* A window that frames an inner control. The inner control is resized
* to fill the client area.
*
*****************************************************************************/
#define FW_MSG(msg) case msg: return ON_##msg(uiMsg, wParam, lParam)
class NO_VTABLE FrameWindow {
public:
static DWORD RunThread(FrameWindow *self, LPVOID lpParameter);
protected:
void SetAcceleratorTable(LPCTSTR pszAccel)
{
_haccel = LoadAccelerators(g_hinst, pszAccel);
}
BOOL SetWindowMenu(LPCTSTR pszMenu)
{
return SetMenu(_hwnd, LoadMenu(g_hinst, pszMenu));
}
virtual LRESULT HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam);
virtual ~FrameWindow() { }
//
// For talking back to yourself (typically from a base class back
// to a derived class). Short-circuits the WndProc wrapper for
// perf. Do not use cross-thread!
//
LRESULT SendSelfMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
{
return HandleMessage(uMsg, wParam, lParam);
}
private:
static LRESULT CALLBACK WndProc(HWND hwnd, UINT uiMsg, WPARAM wParam, LPARAM lParam);
HWND CreateFrameWindow();
protected:
HWND _hwnd;
HWND _hwndChild;
HACCEL _haccel;
LPTSTR _pszQuery;
};
/*****************************************************************************
*
* LVFrame - lvframe.cpp
*
* A FrameWindow that frames a listview in report mode.
*
*****************************************************************************/
#define LM_ITEMACTIVATE (WM_USER + 100) // wParam = iItem
#define LM_GETINFOTIP (WM_USER + 101) // wParam = iItem, lParam -> NMLVGETINFOTIP
#define LM_GETCONTEXTMENU (WM_USER + 102) // wParam = iItem
#define LM_COPYTOCLIPBOARD (WM_USER + 103) // wParam = iMin, lParam = iMax (exclusive)
#define LM_DELETEITEM (WM_USER + 104) // wParam = iItem, lParam = lParam
typedef struct LVFCOLUMN {
UINT cch;
UINT ids;
UINT fmt;
} LVFCOLUMN;
class NO_VTABLE LVFrame : public FrameWindow {
typedef FrameWindow super;
protected:
enum { IDC_LIST = 1 };
BOOL CreateChild(DWORD dwStyle, DWORD dwExStyle);
BOOL AddColumns(const LVFCOLUMN *rgcol);
void *GetLVItem(int iItem);
int GetCurSel() { return ListView_GetCurSel(_hwndChild); }
LRESULT HandleMessage(UINT uiMsg, WPARAM wParam, LPARAM lParam);
private:
LRESULT ON_WM_NOTIFY(UINT uiMsg, WPARAM wParam, LPARAM lParam);
LRESULT ON_WM_COMMAND(UINT uiMsg, WPARAM wParam, LPARAM lParam);
LRESULT ON_WM_CONTEXTMENU(UINT uiMsg, WPARAM wParam, LPARAM lParam);
private:
LVInfoTip _it;
};
/*****************************************************************************
*
* TLFrame - tlframe.cpp
*
* Wraps the Tree class. If I were less lazy, I would merge it into
* this class, but right now Tree is a separate class because I stole
* the code from sdflog...
*
*****************************************************************************/
class NO_VTABLE TLFrame : public LVFrame {
typedef LVFrame super;
protected:
TLFrame(TreeItem *ptiRoot) : _tree(ptiRoot) { }
LRESULT HandleMessage(UINT uiMsg, WPARAM wParam, LPARAM lParam);
BOOL CreateChild(DWORD dwStyle, DWORD dwExStyle);
TreeItem *TLGetCurSel() { return _tree.GetCurSel(); };
private:
LRESULT ON_WM_NOTIFY(UINT uiMsg, WPARAM wParam, LPARAM lParam);
LRESULT ON_LM_ITEMACTIVATE(UINT uiMsg, WPARAM wParam, LPARAM lParam);
LRESULT ON_LM_GETINFOTIP(UINT uiMsg, WPARAM wParam, LPARAM lParam);
LRESULT ON_LM_GETCONTEXTMENU(UINT uiMsg, WPARAM wParam, LPARAM lParam);
LRESULT ON_LM_COPYTOCLIPBOARD(UINT uiMsg, WPARAM wParam, LPARAM lParam);
protected:
Tree _tree;
};
/*****************************************************************************
*
* BGTask
*
*****************************************************************************/
class BGTask
{
protected:
BGTask() : _hDone(CreateEvent(NULL, TRUE, TRUE, NULL)), _fPending(FALSE) { }
BOOL BGConstructed() const { return _hDone != NULL; }
BOOL BGTaskPending() const { return _fPending; }
~BGTask();
BOOL BGStartTask(LPTHREAD_START_ROUTINE pfn, LPVOID Context);
void BGEndTask();
LRESULT BGFilterSetCursor(LRESULT lres);
private:
BOOL _fPending;
HANDLE _hDone;
};
/*****************************************************************************
*
* Parser
*
*****************************************************************************/
class Substring
{
public:
LPTSTR _pszMin; // First character of the substring
LPTSTR _pszMax; // One past the last character of the substring
explicit Substring() { }
explicit Substring(LPCTSTR pszMin, LPCTSTR pszMax)
: _pszMin(CCAST(LPTSTR, pszMin)),
_pszMax(CCAST(LPTSTR, pszMax)) { }
LPTSTR SetStart(LPCTSTR psz)
{
return _pszMin = CCAST(LPTSTR, psz);
}
LPTSTR Start() { return _pszMin; }
SIZE_T Length() const { return _pszMax - _pszMin; }
SIZE_T SetEnd(LPCTSTR psz)
{
_pszMax = CCAST(LPTSTR, psz);
return Length();
}
LPTSTR Finalize() // This method works only on mutable substrings
{
*_pszMax = TEXT('\0');
return _pszMin;
}
};
LPTSTR Parse(LPCTSTR pszFormat, LPCTSTR pszParse, Substring *rgss);
inline _String& operator<<(_String& str, Substring ss)
{
str.Append(ss._pszMin, (int)(ss._pszMax - ss._pszMin));
return str;
}
/*****************************************************************************
*
* CommentParser - Parses checkin comments
*
*****************************************************************************/
class NO_VTABLE CommentParser {
public:
virtual void SetDev(LPCTSTR psz) = 0;
virtual void SetComment(LPCTSTR psz) = 0;
void Reset() { _fHaveComment = FALSE; }
void AddComment(LPTSTR psz);
CommentParser() { Reset(); }
private:
BOOL _fHaveComment;
};
/*****************************************************************************
*
* Tokenizer
*
*****************************************************************************/
class Tokenizer
{
public:
explicit Tokenizer() { }
explicit Tokenizer(LPCTSTR psz) { Restart(psz); }
void Restart(LPCTSTR psz);
LPCTSTR Unparsed() const { return _psz; }
BOOL Token(String& str);
BOOL Finished() const { return !*_psz; }
private:
LPCTSTR _psz;
};
/*****************************************************************************
*
* GetOpt
*
* pszParams is the list of switches that take parameters. By default,
* switches do not take parameters.
*
*****************************************************************************/
class GetOpt
{
public:
GetOpt(LPCTSTR pszParams, LPCTSTR pszArg)
: _pszParams(pszParams), _pszUnparsed(NULL), _tok(pszArg) { }
TCHAR NextSwitch();
BOOL Token() { return _tok.Token(_str); }
BOOL Finished() { return _tok.Finished(); }
LPCTSTR GetValue() const { return _pszValue; }
Tokenizer GetTokenizer() const { return _tok; }
private:
LPCTSTR _pszParams;
LPTSTR _pszUnparsed;
LPTSTR _pszValue;
Tokenizer _tok;
String _str;
};
/*****************************************************************************
*
* WaitCursor
*
*****************************************************************************/
class WaitCursor
{
public:
explicit WaitCursor() : _hcur(SetCursor(g_hcurWait)) { }
~WaitCursor() { SetCursor(_hcur); }
private:
HCURSOR _hcur;
};
/*****************************************************************************
*
* Annoying version-checking functions
*
*****************************************************************************/
inline BOOL VER1GE(UINT A,
UINT a)
{ return A >= a; }
inline BOOL VER2GE(UINT A, UINT B,
UINT a, UINT b)
{ return A > a || (A == a && VER1GE(B,b)); }
inline BOOL VER3GE(UINT A, UINT B, UINT C,
UINT a, UINT b, UINT c)
{ return A > a || (A == a && VER2GE(B,C,b,c)); }
inline BOOL VER4GE(UINT A, UINT B, UINT C, UINT D,
UINT a, UINT b, UINT c, UINT d)
{ return A > a || (A == a && VER3GE(B,C,D,b,c,d)); }
/*****************************************************************************
*
* Globals
*
*****************************************************************************/
struct CGlobals
{
public:
void Initialize();
BOOL IsChurnEnabled() const { return _fChurn; }
const _StringCache& GetSdOpts() const { return _pszSdOpts; }
const _StringCache& GetUserName() const { return _rgpszSettings[SETTING_USERNAME]; }
const _StringCache& GetClientName() const { return _rgpszSettings[SETTING_CLIENTNAME]; }
const _StringCache& GetClientRoot() const { return _rgpszSettings[SETTING_CLIENTROOT]; }
const _StringCache& GetFakeDir() const { return _pszFakeDir; }
const _StringCache& GetLocalRoot() const { return _pszLocalRoot; }
LPCTSTR GetSdPath() const { return _szSd; }
String& FormatBugUrl(String& str, int iBug) const
{
str << _pszBugPagePre << iBug << _pszBugPagePost;
return str;
}
void SetChurn(BOOL fChurn) { _fChurn = fChurn; }
void SetSdOpts(LPCTSTR psz) { _pszSdOpts = psz; }
BOOL IsVersion(UINT major) { return VER1GE(_Major(), major); }
BOOL IsVersion(UINT major, UINT minor)
{ return VER2GE(_Major(), _Minor(), major, minor); }
private:
void _InitSdPath();
void _InitInfo();
void _InitFakeDir();
void _InitServerVersion();
void _InitBugPage();
UINT _Major() { return _rguiVer[VERSION_MAJOR]; }
UINT _Minor() { return _rguiVer[VERSION_MINOR]; }
enum {
SETTING_USERNAME,
SETTING_CLIENTNAME,
SETTING_CLIENTROOT,
SETTING_LOCALDIR,
SETTING_SERVERVERSION,
SETTING_MAX
};
enum {
VERSION_MAJOR,
VERSION_MINOR,
VERSION_BUILD,
VERSION_QFE,
VERSION_MAX,
};
private:
BOOL _fChurn;
_StringCache _pszSdOpts;
_StringCache _pszLocalRoot;
_StringCache _pszFakeDir;
_StringCache _pszBugPagePre;
_StringCache _pszBugPagePost;
_StringCache _rgpszSettings[SETTING_MAX];
UINT _rguiVer[VERSION_MAX];
TCHAR _szSd[MAX_PATH];
};
extern CGlobals GlobalSettings;
#endif