GPL sync + delete value implemented
[reactos.git] / rosapps / sysutils / regexpl / RegistryExplorer.cpp
1 /* $Id: RegistryExplorer.cpp,v 1.2 2000/10/24 20:17:41 narnaoud Exp $
2 *
3 * regexpl - Console Registry Explorer
4 *
5 * Copyright (C) 2000 Nedko Arnaoudov <nedkohome@atia.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; see the file COPYING. If not, write to
19 * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 * Boston, MA 02111-1307, USA.
21 */
22
23 // Registry Explorer.cpp : Defines the entry point for the console application.
24 //
25
26 #include "ph.h"
27 #include "RegistryExplorer.h"
28 #include "Console.h"
29 #include "RegistryKey.h"
30 #include "RegistryTree.h"
31 #include "SecurityDescriptor.h"
32 #include "ArgumentParser.h"
33 #include "ShellCommandsLinkedList.h"
34 #include "ShellCommandExit.h"
35 #include "ShellCommandVersion.h"
36 #include "ShellCommandHelp.h"
37 #include "ShellCommandDir.h"
38 #include "ShellCommandChangeKey.h"
39 #include "ShellCommandValue.h"
40 #include "ShellCommandOwner.h"
41 #include "ShellCommandDACL.h"
42 #include "ShellCommandSACL.h"
43 #include "ShellCommandDOKA.h"
44 #include "ShellCommandConnect.h"
45 #include "ShellCommandNewKey.h"
46 #include "ShellCommandDeleteKey.h"
47 #include "ShellCommandSetValue.h"
48 #include "ShellCommandDeleteValue.h"
49
50 TCHAR pchCurrentKey[PROMPT_BUFFER_SIZE];
51
52 CRegistryTree Tree(PROMPT_BUFFER_SIZE+1);
53 CConsole Console;
54
55 const TCHAR * ppchRootKeys[7] =
56 {
57 _T("HKEY_CLASSES_ROOT"),
58 _T("HKEY_CURRENT_USER"),
59 _T("HKEY_LOCAL_MACHINE"),
60 _T("HKEY_USERS"),
61 _T("HKEY_PERFORMANCE_DATA"),
62 _T("HKEY_CURRENT_CONFIG"),
63 _T("HKEY_DYN_DATA") //win9x only?
64 };
65
66 BOOL g_blnCompletionCycle = TRUE;
67
68 const TCHAR * CompletionCallback(unsigned __int64 & rnIndex, const BOOL *pblnForward, const TCHAR *pchContext, const TCHAR *pchBegin)
69 {
70 #define COMPLETION_BUFFER_SIZE 4096
71 static TCHAR pchBuffer[COMPLETION_BUFFER_SIZE];
72 CRegistryKey *pKey = NULL;
73 CRegistryTree *pTree = NULL;
74 unsigned __int64 nTotalKeys = 0;
75 unsigned __int64 nTotalValues = 0;
76 unsigned __int64 nTotalItems = 0;
77 class CompletionMatch
78 {
79 public:
80 CompletionMatch(const TCHAR *pchText, CompletionMatch **pNext)
81 {
82 BOOL b = _tcschr(pchText,_T(' ')) != NULL;
83 size_t s = _tcslen(pchText);
84 m_pchText = new TCHAR [s+(b?3:1)];
85 if (b)
86 {
87 m_pchText[0] = _T('\"');
88 _tcscpy(m_pchText+1,pchText);
89 m_pchText[s+1] = _T('\"');
90 m_pchText[s+2] = 0;
91 }
92 else
93 {
94 _tcscpy(m_pchText,pchText);
95 }
96 if (m_pchText)
97 {
98 m_pNext = *pNext;
99 *pNext = this;
100 }
101 }
102 ~CompletionMatch()
103 {
104 if (m_pchText)
105 delete m_pchText;
106 if (m_pNext)
107 delete m_pNext;
108 }
109 const TCHAR *GetText(unsigned __int64 dwReverseIndex)
110 {
111 if (dwReverseIndex)
112 {
113 if (m_pNext)
114 return m_pNext->GetText(dwReverseIndex-1);
115 else
116 return NULL;
117 }
118 return m_pchText;
119 }
120 private:
121 TCHAR *m_pchText;
122 CompletionMatch *m_pNext;
123 };
124 CompletionMatch *pRootMatch = NULL;
125
126 BOOL blnCompletionOnKeys = TRUE;
127 BOOL blnCompletionOnValues = TRUE;
128
129 while(*pchContext && _istspace(*pchContext))
130 {
131 pchContext++;
132 }
133
134 /* if ((_tcsnicmp(pchContext,DIR_CMD,DIR_CMD_LENGTH) == 0)||
135 (_tcsnicmp(pchContext,CD_CMD,CD_CMD_LENGTH) == 0)||
136 (_tcsnicmp(pchContext,OWNER_CMD,OWNER_CMD_LENGTH) == 0)||
137 (_tcsnicmp(pchContext,DACL_CMD,DACL_CMD_LENGTH) == 0)||
138 (_tcsnicmp(pchContext,SACL_CMD,SACL_CMD_LENGTH) == 0))
139 {
140 blnCompletionOnValues = FALSE;
141 }*/
142 // else if (_tcsnicmp(pchContext,VALUE_CMD,VALUE_CMD_LENGTH) == 0)
143 // {
144 // blnCompletionOnKeys = FALSE;
145 // }
146
147 const TCHAR *pchKey = _tcsrchr(pchBegin,_T('\\'));
148 DWORD nBufferOffset = 0;
149 if (pchKey)
150 {
151 nBufferOffset = pchKey-pchBegin+1;
152 if (nBufferOffset >= COMPLETION_BUFFER_SIZE-1)
153 {
154 if (pRootMatch) delete pRootMatch;
155 if (pTree)
156 delete pTree;
157 return _T("internal error");
158 }
159 _tcsncpy(pchBuffer,pchBegin,nBufferOffset);
160 pchBuffer[nBufferOffset] = 0;
161 pchBegin = pchKey+1;
162 pTree = new CRegistryTree(Tree);
163 if ((_tcscmp(pTree->GetCurrentPath(),Tree.GetCurrentPath()) != 0)||(!pTree->ChangeCurrentKey(pchBuffer)))
164 {
165 if (pTree)
166 delete pTree;
167 return NULL;
168 }
169 else
170 {
171 pKey = pTree->GetCurrentKey();
172 }
173 }
174 else
175 {
176 pKey = Tree.GetCurrentKey();
177 }
178
179 if (!pKey)
180 {
181 for(unsigned int i = 0 ; i < sizeof(ppchRootKeys)/sizeof(TCHAR *) ; i++)
182 {
183 nTotalKeys++;
184 nTotalItems++;
185 CompletionMatch *p = new CompletionMatch(ppchRootKeys[i],&pRootMatch);
186 if (!p || !p->GetText(0))
187 {
188 if (pRootMatch) delete pRootMatch;
189 if (pTree)
190 delete pTree;
191 return _T("Out of memory");
192 }
193 }
194 }
195 else
196 {
197 CompletionMatch *p;
198 DWORD dwError;
199 if (blnCompletionOnKeys)
200 {
201 /* if (_tcslen(pchBegin) == 0)
202 {
203 p = new CompletionMatch(_T(".."),&pRootMatch);
204 if (!p || !p->GetText(0))
205 {
206 if (pRootMatch) delete pRootMatch;
207 if (pTree)
208 delete pTree;
209 return _T("Out of memory");
210 }
211 nTotalKeys++;
212 nTotalItems++;
213 }
214 */
215 pKey->InitSubKeyEnumeration();
216 TCHAR *pchSubKeyName;
217 while ((pchSubKeyName = pKey->GetSubKeyName(dwError)) != NULL)
218 {
219 if (_tcsnicmp(pchSubKeyName,pchBegin,_tcslen(pchBegin)) == 0)
220 {
221 nTotalKeys++;
222 nTotalItems++;
223 p = new CompletionMatch(pchSubKeyName,&pRootMatch);
224 if (!p || !p->GetText(0))
225 {
226 if (pRootMatch) delete pRootMatch;
227 if (pTree)
228 delete pTree;
229 return _T("Out of memory");
230 }
231 }
232 }
233 if ((dwError != ERROR_SUCCESS)&&(dwError != ERROR_NO_MORE_ITEMS))
234 {
235 if (pRootMatch) delete pRootMatch;
236 if (pTree)
237 delete pTree;
238 return _T("error");
239 }
240 }
241
242 if (blnCompletionOnValues)
243 {
244 pKey->InitValueEnumeration();
245 TCHAR *pchValueName;
246 DWORD dwValueNameLength, dwMaxValueNameLength;
247 dwError = pKey->GetMaxValueNameLength(dwMaxValueNameLength);
248 if (dwError != ERROR_SUCCESS)
249 {
250 if (pRootMatch) delete pRootMatch;
251 if (pTree)
252 delete pTree;
253 return _T("error");
254 }
255
256 dwMaxValueNameLength++;
257 pchValueName = new TCHAR [dwMaxValueNameLength];
258 if (!pchValueName)
259 {
260 if (pRootMatch) delete pRootMatch;
261 if (pTree)
262 delete pTree;
263 return _T("Out of memory");
264 }
265 for(;;)
266 {
267 dwValueNameLength = dwMaxValueNameLength;
268 //dwValueSize = dwMaxValueSize;
269 dwError = pKey->GetNextValue(pchValueName,dwValueNameLength,NULL,NULL,NULL);
270 if (dwError == ERROR_NO_MORE_ITEMS) break;
271 if (dwError != ERROR_SUCCESS)
272 {
273 if (pRootMatch) delete pRootMatch;
274 if (pTree)
275 delete pTree;
276 return _T("error");
277 }
278
279 if (((dwValueNameLength == 0) && (_tcslen(pchBegin) == 0))||
280 (_tcsnicmp(pchValueName,pchBegin,_tcslen(pchBegin)) == 0))
281 {
282 nTotalValues++;
283 nTotalItems++;
284 p = new CompletionMatch((dwValueNameLength == 0)?_T("(Default)"):pchValueName,&pRootMatch);
285 if (!p || !p->GetText(0))
286 {
287 if (pRootMatch) delete pRootMatch;
288 if (pTree)
289 delete pTree;
290 return _T("Out of memory");
291 }
292 }
293 } // for
294 delete [] pchValueName;
295 }
296 }
297 if (rnIndex >= nTotalItems)
298 rnIndex = nTotalItems-1;
299 if (pblnForward)
300 {
301 if (*pblnForward)
302 {
303 rnIndex++;
304 if (rnIndex >= nTotalItems)
305 {
306 if (g_blnCompletionCycle)
307 rnIndex = 0;
308 else
309 rnIndex--;
310 }
311 }
312 else
313 {
314 if (rnIndex)
315 rnIndex--;
316 else if (g_blnCompletionCycle)
317 rnIndex = nTotalItems-1;
318 }
319 }
320
321 const TCHAR *pchName;
322 if (nTotalItems == 0)
323 {
324 if (pRootMatch)
325 delete pRootMatch;
326 if (pTree)
327 delete pTree;
328 return NULL;
329 }
330 ASSERT(rnIndex < nTotalItems);
331 pchName = pRootMatch->GetText(nTotalItems-rnIndex-1);
332 if (pchName == NULL)
333 {
334 if (pRootMatch)
335 delete pRootMatch;
336 if (pTree)
337 delete pTree;
338 return _T("internal error");
339 }
340 DWORD dwBufferFull = _tcslen(pchName);
341 if (dwBufferFull >= COMPLETION_BUFFER_SIZE-nBufferOffset)
342 {
343 dwBufferFull = COMPLETION_BUFFER_SIZE-1-nBufferOffset;
344 }
345 _tcsncpy(pchBuffer+nBufferOffset,pchName,dwBufferFull);
346 if ((dwBufferFull < COMPLETION_BUFFER_SIZE-1)&&(rnIndex < nTotalKeys))
347 pchBuffer[nBufferOffset+dwBufferFull++] = _T('\\');
348 pchBuffer[nBufferOffset+dwBufferFull] = 0;
349 if (pTree)
350 delete pTree;
351 if (pRootMatch)
352 delete pRootMatch;
353 return pchBuffer;
354 }
355
356 BOOL blnCommandExecutionInProgress = FALSE;
357
358 BOOL WINAPI HandlerRoutine(DWORD dwCtrlType)
359 {
360 switch(dwCtrlType)
361 {
362 case CTRL_C_EVENT:
363 case CTRL_BREAK_EVENT:
364 if (blnCommandExecutionInProgress)
365 {
366 /* Beep(1000,100);
367 Beep(2000,100);
368 Beep(3000,100);
369 Beep(4000,100);
370 Beep(5000,100);
371 Beep(4000,100);
372 Beep(3000,100);
373 Beep(2000,100);
374 Beep(1000,100);*/
375 Console.Write(_T("\n"));
376 Console.DisableWrite();
377 }
378 return TRUE;
379 default:
380 return FALSE;
381 }
382 }
383
384 //int _tmain(/*int argc, TCHAR* argv[], TCHAR* envp[]*/)
385 int main ()
386 {
387 CShellCommandsLinkedList CommandsList(Console);
388
389 CShellCommandExit ExitCommand;
390 CommandsList.AddCommand(&ExitCommand);
391
392 CShellCommandVersion VersionCommand;
393 CommandsList.AddCommand(&VersionCommand);
394
395 CShellCommandHelp HelpCommand(CommandsList);
396 CommandsList.AddCommand(&HelpCommand);
397
398 CShellCommandDir DirCommand(Tree);
399 CommandsList.AddCommand(&DirCommand);
400
401 CShellCommandChangeKey ChangeKeyCommand(Tree);
402 CommandsList.AddCommand(&ChangeKeyCommand);
403
404 CShellCommandValue ValueCommand(Tree);
405 CommandsList.AddCommand(&ValueCommand);
406
407 CShellCommandOwner OwnerCommand(Tree);
408 CommandsList.AddCommand(&OwnerCommand);
409
410 CShellCommandDACL DACLCommand(Tree);
411 CommandsList.AddCommand(&DACLCommand);
412
413 CShellCommandSACL SACLCommand(Tree);
414 CommandsList.AddCommand(&SACLCommand);
415
416 CShellCommandDOKA DOKACommand(Tree);
417 CommandsList.AddCommand(&DOKACommand);
418
419 CShellCommandConnect ConnectCommand(Tree);
420 CommandsList.AddCommand(&ConnectCommand);
421
422 CShellCommandNewKey NewKeyCommand(Tree);
423 CommandsList.AddCommand(&NewKeyCommand);
424
425 CShellCommandDeleteKey DeleteKeyCommand(Tree);
426 CommandsList.AddCommand(&DeleteKeyCommand);
427
428 CShellCommandSetValue SetValueCommand(Tree);
429 CommandsList.AddCommand(&SetValueCommand);
430
431 CShellCommandDeleteValue DeleteValueCommand(Tree);
432 CommandsList.AddCommand(&DeleteValueCommand);
433
434 CArgumentParser Parser;
435
436 int nRetCode = 0;
437
438 // input buffer size in chars
439 #define INPUT_BUFFER_SIZE 1024
440 //#define INPUT_BUFFER_SIZE 128
441 //#define INPUT_BUFFER_SIZE 10
442
443 TCHAR *pchCommand;
444
445 pchCommand = Console.Init(INPUT_BUFFER_SIZE,10);
446 if (pchCommand == NULL)
447 {
448 _ftprintf(stderr,_T("Cannot initialize console.\n"));
449 goto Abort;
450 }
451
452 Console.SetReplaceCompletionCallback(CompletionCallback);
453
454 WORD wOldConsoleAttribute;
455 if (!Console.GetTextAttribute(wOldConsoleAttribute)) goto Abort;
456
457 Console.SetTitle(_T("Registry Explorer"));
458 Console.SetTextAttribute(FOREGROUND_BLUE|FOREGROUND_GREEN|FOREGROUND_RED|FOREGROUND_INTENSITY);
459
460 VERIFY(SetConsoleCtrlHandler((PHANDLER_ROUTINE)HandlerRoutine,TRUE));
461
462 if (!Console.Write(HELLO_MSG
463 //(_L(__TIMESTAMP__))
464 )) goto Abort;
465
466 Tree.SetDesiredOpenKeyAccess(KEY_READ);
467
468 GetCommand:
469 // prompt
470 // TODO: make prompt user-customizable
471 Console.EnableWrite();
472 _tcscpy(pchCurrentKey,Tree.GetCurrentPath());
473 Console.Write(pchCurrentKey);
474 Console.Write(_T("\n# "));
475 Console.FlushInputBuffer();
476
477 blnCommandExecutionInProgress = FALSE;
478
479 // Set command line color
480 // Console.SetTextAttribute(/*FOREGROUND_BLUE|*/FOREGROUND_GREEN|FOREGROUND_RED|FOREGROUND_INTENSITY);
481 if (!Console.ReadLine()) goto Abort;
482
483 // Set normal color
484 // Console.SetTextAttribute(FOREGROUND_BLUE|FOREGROUND_GREEN|FOREGROUND_RED|FOREGROUND_INTENSITY);
485
486 Console.BeginScrollingOperation();
487 blnCommandExecutionInProgress = TRUE;
488
489
490 // Parse command line (1st step - convert to multi sz)
491 Parser.SetArgumentList(pchCommand);
492
493 int nCommandReturnValue;
494 switch(CommandsList.Execute(Parser,nCommandReturnValue))
495 {
496 case -1: // not recognized command
497 {
498 Parser.ResetArgumentIteration();
499 TCHAR *pchCommandItself = Parser.GetNextArgument();
500 size_t cmdlen = _tcslen(pchCommandItself);
501 if ((!cmdlen)||
502 (pchCommandItself[cmdlen-1] != _T('\\'))||
503 (Parser.GetNextArgument())||
504 (!Tree.ChangeCurrentKey(pchCommandItself)))
505 {
506 Console.Write(_T("Unknown command \""));
507 Console.Write(pchCommandItself);
508 Console.Write(_T("\"\n"));
509 }
510 }
511 case -2: // empty line
512 goto GetCommand;
513 case 0: // exit command
514 nRetCode = 0;
515 Console.SetTextAttribute(wOldConsoleAttribute);
516 goto Exit;
517 default:
518 Console.Write(_T("\n"));
519 goto GetCommand;
520 }
521
522 Abort:
523 _ftprintf(stderr,_T("Abnormal program termination.\nPlease report bugs to ") EMAIL _T("\n"));
524 nRetCode = 1;
525 Exit:
526 return nRetCode;
527 }