Something went wrong. Try again.
Reactos
Something went wrong. Try again.
C++
at master
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515/* * regexpl - Console Registry Explorer * * Copyright (C) 2000-2005 Nedko Arnaudov <nedko@users.sourceforge.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; see the file COPYING. If not, write to * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */
// Completion.cpp : Defines the completion related functions.#include "ph.h"#include "RegistryKey.h"#include "RegistryTree.h"
#define COMPLETION_BUFFER_SIZE 4096
extern CRegistryTree Tree;
BOOL g_blnCompletionCycle = TRUE;
class CCompletionMatch{public: CCompletionMatch() { m_pNext = m_pPrev = NULL; m_pszText = NULL; };
BOOL Init(const TCHAR *pszText) { // find the offset to "unique" part const TCHAR *pszUnique = _tcsrchr(pszText,_T('\\')); pszUnique = pszUnique?(pszUnique+1):pszText; BOOL b = _tcschr(pszUnique,_T(' ')) != NULL; // has it spaces in it ??? size_t s = _tcslen(pszText);
if (m_pszText) delete[] m_pszText;
m_pszText = new (std::nothrow) TCHAR [s+(b?3:1)]; // if we have spaces in unique part, we need 2 addtional chars for "
if (!m_pszText) return FALSE;
ASSERT(pszText <= pszUnique); s = pszUnique - pszText; // calculate offset of the unique part if (s) _tcsncpy(m_pszText,pszText,s);
if (b) m_pszText[s++] = _T('\"');
_tcscpy(m_pszText+s,pszUnique);
if (b) _tcscat(m_pszText,_T("\""));
return TRUE; }
~CCompletionMatch() { if (m_pszText) delete[] m_pszText; }
private: TCHAR *m_pszText; BOOL m_blnIsKey; CCompletionMatch *m_pNext; CCompletionMatch *m_pPrev; friend class CCompletionList;};
class CCompletionList{public: CCompletionList(); ~CCompletionList();
BOOL IsNewCompletion(const TCHAR *pszContext, const TCHAR *pszBegin, BOOL& rblnNew); BOOL Add(const TCHAR *pszText, BOOL blnIsKey); const TCHAR *Get(unsigned __int64 nIndex, BOOL& rblnIsKey); unsigned __int64 GetCount(); const TCHAR * GetContext(); const TCHAR * GetBegin(); void DeleteList(); void Invalidate();
private: CCompletionMatch *m_pHead; // head of completions linked list CCompletionMatch *m_pTail; // tail of completions linked list CCompletionMatch *m_pLastSearched; unsigned int m_nLastSearched; TCHAR *m_pszContext; TCHAR *m_pszBegin; TCHAR *m_pszCurrentKey; unsigned __int64 m_nCount;} g_Completion;
// --- begin of CCompletionList implementation ---CCompletionList::CCompletionList(){ m_pHead = NULL; m_pTail = NULL; m_nCount = 0; m_pLastSearched = NULL; m_pszContext = NULL; m_pszBegin = NULL; m_pszCurrentKey = NULL;}
CCompletionList::~CCompletionList(){ DeleteList();
if (m_pszContext) delete[] m_pszContext;
if (m_pszBegin) delete[] m_pszBegin;
if (m_pszCurrentKey) delete[] m_pszCurrentKey;}
void CCompletionList::Invalidate(){ if (m_pszCurrentKey) { delete[] m_pszCurrentKey; m_pszCurrentKey = NULL; }}
BOOL CCompletionList::IsNewCompletion(const TCHAR *pszContext, const TCHAR *pszBegin, BOOL& rblnNew){ const TCHAR *pszCurrentKey = Tree.GetCurrentPath(); if (!m_pszContext || !m_pszBegin || !m_pszCurrentKey || (_tcscmp(m_pszContext,pszContext) != 0) || (_tcscmp(m_pszBegin,pszBegin) != 0) || (_tcscmp(m_pszCurrentKey,pszCurrentKey))) { // new completion DeleteList(); rblnNew = TRUE; if (m_pszContext) { delete[] m_pszContext; m_pszContext = NULL; }
if (m_pszBegin) { delete[] m_pszBegin; m_pszBegin = NULL; }
if (m_pszCurrentKey) { delete[] m_pszCurrentKey; m_pszCurrentKey = NULL; }
size_t s = _tcslen(pszContext); m_pszContext = new (std::nothrow) TCHAR[s+1]; if (!m_pszContext) return FALSE; _tcscpy(m_pszContext,pszContext);
s = _tcslen(pszBegin); m_pszBegin = new (std::nothrow) TCHAR[s+1]; if (!m_pszBegin) { delete[] m_pszContext; m_pszContext = NULL; return FALSE; } _tcscpy(m_pszBegin,pszBegin);
s = _tcslen(pszCurrentKey); m_pszCurrentKey = new (std::nothrow) TCHAR[s+1]; if (!m_pszCurrentKey) { delete[] m_pszContext; delete[] m_pszBegin; m_pszContext = NULL; m_pszBegin = NULL; return FALSE; } _tcscpy(m_pszCurrentKey,pszCurrentKey);
return TRUE; }
rblnNew = FALSE; return TRUE;}
BOOL CCompletionList::Add(const TCHAR *pszText, BOOL blnIsKey){ if (_tcsnicmp(pszText,m_pszBegin,_tcslen(m_pszBegin)) != 0) return TRUE; CCompletionMatch *pNode = new (std::nothrow) CCompletionMatch; if (!pNode) return FALSE; if (!pNode->Init(pszText)) return FALSE;
ASSERT(pNode->m_pszText); ASSERT(pNode->m_pNext == NULL);
// add new node to tail pNode->m_blnIsKey = blnIsKey; if (m_pTail) { pNode->m_pPrev = m_pTail; ASSERT(m_pTail->m_pNext == NULL); m_pTail->m_pNext = pNode; m_pTail = pNode; } else { ASSERT(m_pHead == NULL); m_pHead = m_pTail = pNode; }
m_nCount++;
m_pLastSearched = NULL;
return TRUE;}
const TCHAR * CCompletionList::Get(unsigned __int64 nIndex, BOOL& rblnIsKey){ ASSERT(nIndex < m_nCount); BOOL blnForward = FALSE; CCompletionMatch *pNode = NULL;
unsigned __int64 nRelativeIndex = 0;
if (m_pLastSearched) { pNode = m_pLastSearched; blnForward = nIndex > m_nLastSearched; nRelativeIndex = blnForward?(nIndex-m_nLastSearched):(m_nLastSearched-nIndex); if ((nRelativeIndex > nIndex)||(nRelativeIndex > m_nCount-nIndex-1)) pNode = NULL; // seraching from tail or from head is more effective }
if (!pNode && (nIndex <= m_nCount/2)) { // search from head pNode = m_pHead; blnForward = TRUE; nRelativeIndex = nIndex; }
if (!pNode) { // search from tail pNode = m_pTail; blnForward = FALSE; nRelativeIndex = m_nCount-nIndex-1; }
while(pNode) { if (nRelativeIndex == 0) { m_nLastSearched = nIndex; m_pLastSearched = pNode; rblnIsKey = pNode->m_blnIsKey; if (!pNode->m_pszText) ASSERT(FALSE); return pNode->m_pszText; }
nRelativeIndex--;
pNode = blnForward?(pNode->m_pNext):(pNode->m_pPrev); }
ASSERT(FALSE); return NULL;}
unsigned __int64 CCompletionList::GetCount(){ return m_nCount;}
const TCHAR * CCompletionList::GetContext(){ return m_pszContext;}
const TCHAR * CCompletionList::GetBegin(){ return m_pszBegin;}
void CCompletionList::DeleteList(){ CCompletionMatch *pNode; while(m_pHead) { pNode = m_pHead; m_pHead = m_pHead->m_pNext; delete pNode; } m_pTail = NULL; ASSERT(m_pHead == NULL); m_nCount = 0;}
// --- end of CCompletionList implementation ---
BOOL FillCompletion(const TCHAR *pszKey){ g_Completion.DeleteList(); LONG nError; CRegistryKey Key; TCHAR *pszSubkeyName = NULL; DWORD dwMaxSubkeyNameLength; TCHAR *pszValueName = NULL; DWORD dwMaxValueNameSize;
if (!Tree.GetKey(pszKey?pszKey:_T("."),KEY_ENUMERATE_SUB_KEYS|KEY_QUERY_VALUE,Key)) return FALSE;
BOOL blnCompletionOnKeys = TRUE; BOOL blnCompletionOnValues = TRUE;
/* if ((_tcsnicmp(pchContext,DIR_CMD,DIR_CMD_LENGTH) == 0)|| (_tcsnicmp(pchContext,CD_CMD,CD_CMD_LENGTH) == 0)|| (_tcsnicmp(pchContext,OWNER_CMD,OWNER_CMD_LENGTH) == 0)|| (_tcsnicmp(pchContext,DACL_CMD,DACL_CMD_LENGTH) == 0)|| (_tcsnicmp(pchContext,SACL_CMD,SACL_CMD_LENGTH) == 0)) { blnCompletionOnValues = FALSE; }*/// else if (_tcsnicmp(pchContext,VALUE_CMD,VALUE_CMD_LENGTH) == 0)// {// blnCompletionOnKeys = FALSE;// }
size_t nKeyNameSize = 0; if (pszKey) { nKeyNameSize = _tcslen(pszKey); if (_tcscmp(pszKey,_T("\\"))) nKeyNameSize++; }
if (blnCompletionOnKeys) { nError = Key.GetSubkeyNameMaxLength(dwMaxSubkeyNameLength); if (nError != ERROR_SUCCESS) return FALSE;
pszSubkeyName = new (std::nothrow) TCHAR[nKeyNameSize+dwMaxSubkeyNameLength+1]; if (!pszSubkeyName) goto Abort;
if (pszKey) _stprintf(pszSubkeyName,_tcscmp(pszKey,_T("\\"))?_T("%s\\"):_T("%s"),pszKey);
Key.InitSubkeyEnumeration(pszSubkeyName+nKeyNameSize,dwMaxSubkeyNameLength); while ((nError = Key.GetNextSubkeyName()) == ERROR_SUCCESS) if (!g_Completion.Add(pszSubkeyName,TRUE)) { ASSERT(FALSE); goto Abort; } if ((nError != ERROR_SUCCESS)&&(nError != ERROR_NO_MORE_ITEMS)) { ASSERT(FALSE); goto Abort; } }
if (blnCompletionOnValues) { nError = Key.GetMaxValueNameLength(dwMaxValueNameSize); if (nError != ERROR_SUCCESS) { ASSERT(FALSE); goto Abort; }
pszValueName = new (std::nothrow) TCHAR[nKeyNameSize+dwMaxValueNameSize+1]; if (!pszValueName) goto Abort;
if (pszKey) _stprintf(pszValueName,_tcscmp(pszKey,_T("\\"))?_T("%s\\"):_T("%s"),pszKey);
Key.InitValueEnumeration(pszValueName+nKeyNameSize,dwMaxValueNameSize,NULL,0,NULL); while((nError = Key.GetNextValue()) == ERROR_SUCCESS) if (!g_Completion.Add(pszValueName,FALSE)) { ASSERT(FALSE); goto Abort; } if ((nError != ERROR_SUCCESS)&&(nError != ERROR_NO_MORE_ITEMS)) { ASSERT(FALSE); goto Abort; } }
if (pszValueName) delete[] pszValueName; if (pszSubkeyName) delete[] pszSubkeyName; return TRUE;Abort: if (pszValueName) delete[] pszValueName; if (pszSubkeyName) delete[] pszSubkeyName; return FALSE;}
const TCHAR * CompletionCallback(unsigned __int64 & rnIndex, const BOOL *pblnForward, const TCHAR *pszContext, const TCHAR *pszBegin){ static TCHAR pszBuffer[COMPLETION_BUFFER_SIZE];
// Find first non-white space in context while(*pszContext && _istspace(*pszContext)) pszContext++;
BOOL blnNewCompletion = TRUE; if (!g_Completion.IsNewCompletion(pszContext,pszBegin,blnNewCompletion)) { ASSERT(FALSE); return NULL; }
if (blnNewCompletion) { _tcsncpy(pszBuffer,pszBegin,COMPLETION_BUFFER_SIZE-1); pszBuffer[COMPLETION_BUFFER_SIZE-1] = 0; TCHAR *pszSeparator = pszBuffer; // set it to aby non null value if (_tcscmp(pszBuffer,_T("\\"))) { pszSeparator = _tcsrchr(pszBuffer,_T('\\')); if (pszSeparator) *pszSeparator = 0; }
if (!FillCompletion(pszSeparator?pszBuffer:NULL)) return NULL; }
unsigned __int64 nTotalItems = g_Completion.GetCount(); if (nTotalItems == 0) return NULL;
if (rnIndex >= nTotalItems) rnIndex = nTotalItems-1;
if (pblnForward) { if (*pblnForward) { rnIndex++; if (rnIndex >= nTotalItems) { if (g_blnCompletionCycle) rnIndex = 0; else rnIndex--; } } else { if (rnIndex) rnIndex--; else if (g_blnCompletionCycle) rnIndex = nTotalItems-1; } } BOOL blnIsKey = FALSE; const TCHAR *pszName = g_Completion.Get(rnIndex,blnIsKey);
ASSERT(pszName);
_sntprintf(pszBuffer,COMPLETION_BUFFER_SIZE-1,_T("%s%s"),pszName,(blnIsKey?_T("\\"):_T(""))); pszBuffer[COMPLETION_BUFFER_SIZE-1] = 0; return pszBuffer;}
void InvalidateCompletion(){ g_Completion.Invalidate();}