[REGEXPL]
[reactos.git] / rosapps / applications / sysutils / regexpl / ShellCommandDir.cpp
1 /* $Id$
2 *
3 * regexpl - Console Registry Explorer
4 *
5 * Copyright (C) 2000-2005 Nedko Arnaudov <nedko@users.sourceforge.net>
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 // ShellCommandDir.cpp: implementation of the CShellCommandDir class.
24 //
25 //////////////////////////////////////////////////////////////////////
26
27 #include "ph.h"
28 #include "RegistryExplorer.h"
29 #include "ShellCommandDir.h"
30 #include "RegistryTree.h"
31 #include "RegistryKey.h"
32 #include "Pattern.h"
33
34 // *** THIS SHOULD GO IN A MINGW/ROS HEADER (tchar.h ???) - Begin
35 #if 1 // #ifndef _ui64tot ???
36 #ifdef _UNICODE
37 #define _ui64tot _ui64tow
38 #else
39 #define _ui64tot _ui64toa
40 #endif
41 #endif
42 // *** THIS SHOULD GO IN A MINGW/ROS HEADER - End
43
44 #define DIR_CMD _T("DIR")
45 #define DIR_CMD_LENGTH COMMAND_LENGTH(DIR_CMD)
46 #define DIR_CMD_SHORT_DESC DIR_CMD _T(" command lists keys and values of any key.\n")
47
48 //////////////////////////////////////////////////////////////////////
49 // Construction/Destruction
50 //////////////////////////////////////////////////////////////////////
51
52 CShellCommandDir::CShellCommandDir(CRegistryTree& rTree):m_rTree(rTree)
53 {
54 }
55
56 CShellCommandDir::~CShellCommandDir()
57 {
58 }
59
60 BOOL CShellCommandDir::Match(const TCHAR *pchCommand)
61 {
62 if (_tcsicmp(pchCommand,DIR_CMD) == 0)
63 return TRUE;
64 if (_tcsnicmp(pchCommand,DIR_CMD _T(".."),DIR_CMD_LENGTH+2*sizeof(TCHAR)) == 0)
65 return TRUE;
66 if (_tcsnicmp(pchCommand,DIR_CMD _T("/"),DIR_CMD_LENGTH+1*sizeof(TCHAR)) == 0)
67 return TRUE;
68 if (_tcsnicmp(pchCommand,DIR_CMD _T("\\"),DIR_CMD_LENGTH+1*sizeof(TCHAR)) == 0)
69 return TRUE;
70 return FALSE;
71 }
72
73 int CShellCommandDir::Execute(CConsole &rConsole, CArgumentParser& rArguments)
74 {
75 rArguments.ResetArgumentIteration();
76
77 BOOL blnDo = TRUE,blnBadParameter, blnHelp = FALSE;
78 TCHAR *pszParameter;
79 TCHAR *pszCommandItself = rArguments.GetNextArgument();
80 TCHAR *pszKey = NULL;
81
82 if ((_tcsnicmp(pszCommandItself,DIR_CMD _T(".."),DIR_CMD_LENGTH+2*sizeof(TCHAR)) == 0)||
83 (_tcsnicmp(pszCommandItself,DIR_CMD _T("\\"),DIR_CMD_LENGTH+1*sizeof(TCHAR)) == 0))
84 {
85 pszKey = pszCommandItself + DIR_CMD_LENGTH;
86 }
87 else if (_tcsnicmp(pszCommandItself,DIR_CMD _T("/"),DIR_CMD_LENGTH+1*sizeof(TCHAR)) == 0)
88 {
89 pszParameter = pszCommandItself + DIR_CMD_LENGTH;
90 goto CheckDirArgument;
91 }
92
93 while((pszParameter = rArguments.GetNextArgument()) != NULL)
94 {
95 CheckDirArgument:
96 blnBadParameter = FALSE;
97 if ((_tcsicmp(pszParameter,_T("/?")) == 0)
98 ||(_tcsicmp(pszParameter,_T("-?")) == 0))
99 {
100 blnHelp = TRUE;
101 blnDo = pszKey != NULL;
102 }
103 else if (!pszKey)
104 {
105 pszKey = pszParameter;
106 blnDo = TRUE;
107 }
108 else
109 {
110 blnBadParameter = TRUE;
111 }
112 if (blnBadParameter)
113 {
114 rConsole.Write(_T("Bad parameter: "));
115 rConsole.Write(pszParameter);
116 rConsole.Write(_T("\n"));
117 }
118 }
119
120 const TCHAR *pszPattern = PATTERN_MATCH_ALL;
121 const TCHAR *pszPath = _T(".");
122
123 if (pszKey)
124 {
125 pszPath = pszKey;
126
127 TCHAR *pch = pszKey;
128 while(*pch) // search end of string
129 pch++;
130
131 if (pch > pszKey) // last non-null char
132 pch--;
133
134 if (*pch != _T('\\'))
135 {
136 while ((pch > pszKey) && (*pch != _T('\\')))
137 pch--;
138
139 if (*pch == _T('\\'))
140 {
141 pszPattern = pch+1;
142
143 if (pch > pszKey)
144 {
145 ASSERT(*pch == _T('\\'));
146 *pch = 0;
147 }
148 else if (*pch == _T('\\'))
149 {
150 pszPath = _T("\\");
151 }
152 }
153 else
154 {
155 pszPattern = pszKey;
156 pszPath = _T(".");
157 }
158 }
159 }
160
161 CRegistryKey Key;
162
163 if (!m_rTree.GetKey(pszPath,KEY_ENUMERATE_SUB_KEYS|KEY_QUERY_VALUE,Key))
164 {
165 const TCHAR *pszErrorMsg = m_rTree.GetLastErrorDescription();
166 rConsole.Write(pszErrorMsg);
167 blnDo = FALSE;
168 }
169
170 if (blnHelp)
171 {
172 rConsole.Write(GetHelpString());
173 }
174
175 LONG nError;
176
177 if (!blnDo)
178 return 0;
179
180 rConsole.Write(_T("\n Key is "));
181 rConsole.Write(Key.GetKeyName());
182
183 if (!Key.IsRoot())
184 {
185 rConsole.Write(_T("\n Last modify time is "));
186 rConsole.Write(Key.GetLastWriteTime());
187 }
188
189 rConsole.Write(_T("\n\n"));
190 unsigned __int64 nTotalItems = 0;
191
192 try
193 {
194 ASSERT(nTotalItems == 0);
195 rConsole.Write(_T("\t(KEY)\t\t\t\t..\\\n")); // parent key abstraction
196 nTotalItems = 1;
197
198 DWORD dwMaxSubkeyNameLength;
199 nError = Key.GetSubkeyNameMaxLength(dwMaxSubkeyNameLength);
200 if (nError != ERROR_SUCCESS)
201 throw nError;
202
203 TCHAR *pszSubkeyNameBuffer = new (std::nothrow) TCHAR[dwMaxSubkeyNameLength];
204 if (!pszSubkeyNameBuffer)
205 throw ERROR_OUTOFMEMORY;
206
207 Key.InitSubkeyEnumeration(pszSubkeyNameBuffer,dwMaxSubkeyNameLength);
208 while ((nError = Key.GetNextSubkeyName()) == ERROR_SUCCESS)
209 {
210 if (PatternMatch(pszPattern,pszSubkeyNameBuffer))
211 {
212 rConsole.Write(_T("\t(KEY)\t\t\t\t"));
213 rConsole.Write(pszSubkeyNameBuffer);
214 rConsole.Write(_T("\\\n"));
215 nTotalItems++;
216 }
217 }
218
219 delete[] pszSubkeyNameBuffer;
220
221 if (nError != ERROR_NO_MORE_ITEMS)
222 throw nError;
223
224 DWORD dwMaxValueNameBufferSize;
225 nError = Key.GetMaxValueNameLength(dwMaxValueNameBufferSize);
226 if (nError != ERROR_SUCCESS)
227 throw nError;
228
229 TCHAR *pchValueNameBuffer = new (std::nothrow) TCHAR[dwMaxValueNameBufferSize];
230 if (!pchValueNameBuffer)
231 throw ERROR_OUTOFMEMORY;
232
233
234 DWORD Type;
235 Key.InitValueEnumeration(pchValueNameBuffer,
236 dwMaxValueNameBufferSize,
237 NULL,
238 0,
239 &Type);
240
241 DWORD dwValueNameActualLength;
242 const TCHAR *pszValueTypeName;
243 unsigned int nTabSize = rConsole.GetTabWidth();
244 unsigned int nTabs;
245 while((nError = Key.GetNextValue(&dwValueNameActualLength)) == ERROR_SUCCESS)
246 {
247 if (PatternMatch(pszPattern,pchValueNameBuffer))
248 {
249 rConsole.Write(_T("\t"));
250 pszValueTypeName = CRegistryKey::GetValueTypeName(Type);
251 nTabs = _tcslen(pszValueTypeName)/nTabSize;
252 nTabs = (nTabs < 4)?(4-nTabs):1;
253 rConsole.Write(pszValueTypeName);
254 while(nTabs--)
255 rConsole.Write(_T("\t"));
256 rConsole.Write((dwValueNameActualLength == 0)?_T("(Default)"):pchValueNameBuffer);
257 rConsole.Write(_T("\n"));
258 nTotalItems++;
259 }
260 }
261
262 delete[] pchValueNameBuffer;
263
264 if (nError != ERROR_NO_MORE_ITEMS)
265 throw nError;
266
267 } // try
268 catch (LONG nError)
269 {
270 rConsole.Write(_T("Error "));
271 TCHAR Buffer[256];
272 rConsole.Write(_itoa(nError,Buffer,10));
273 rConsole.Write(_T("\n"));
274 }
275
276 rConsole.Write(_T("\n Total: "));
277 TCHAR Buffer[256];
278 rConsole.Write(_ui64tot(nTotalItems,Buffer,10));
279 rConsole.Write(_T(" item(s) listed.\n"));
280
281 return 0;
282 }
283
284 const TCHAR * CShellCommandDir::GetHelpString()
285 {
286 return DIR_CMD_SHORT_DESC
287 _T("Syntax: ") DIR_CMD _T(" [<PATH>\\][<PATTERN>] [/?]\n\n")
288 _T(" <PATH> - Optional relative path to the key on which command will be executed\n")
289 _T(" <PATTERN> - Optional pattern. Default is the all matching pattern.")
290 _T(" /? - This help.\n\n")
291 _T("Without parameters, command lists keys and values of current key.\n");
292 }
293
294 const TCHAR * CShellCommandDir::GetHelpShortDescriptionString()
295 {
296 return DIR_CMD_SHORT_DESC;
297 }