e311172b07c860911664eec87bc42d444a886f6b
[reactos.git] / rosapps / sysutils / regnav.c
1 /* $Id: regnav.c,v 1.2 1999/05/28 19:49:46 ea Exp $
2 *
3 * regnav.c
4 *
5 * Copyright (c) 1998, 1999 Emanuele Aliberti
6 *
7 * --------------------------------------------------------------------
8 *
9 * This software is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Library General Public License as
11 * published by the Free Software Foundation; either version 2 of the
12 * License, or (at your option) any later version.
13 *
14 * This software is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Library General Public License for more details.
18 *
19 * You should have received a copy of the GNU Library General Public
20 * License along with this software; see the file COPYING.LIB. If
21 * not, write to the Free Software Foundation, Inc., 675 Mass Ave,
22 * Cambridge, MA 02139, USA.
23 *
24 * --------------------------------------------------------------------
25 * ReactOS system registry console navigation tool.
26 */
27 //#define UNICODE
28 #include <windows.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <tchar.h>
32 #include <assert.h>
33 #include "win32err.h"
34
35 #define INPUT_BUFFER_SIZE 512
36 #define COMMAND_NOT_FOUND NULL
37 #define CURRENT_PATH_SIZE 1024
38
39 LPCTSTR STR_HKEY_CLASSES_ROOT = _TEXT("HKEY_CLASSES_ROOT");
40 LPCTSTR STR_HKEY_CURRENT_USER = _TEXT("HKEY_CURRENT_USER");
41 LPCTSTR STR_HKEY_LOCAL_MACHINE = _TEXT("HKEY_LOCAL_MACHINE");
42 LPCTSTR STR_HKEY_USERS = _TEXT("HKEY_USERS");
43 LPCTSTR STR_HKEY_CURRENT_CONFIG = _TEXT("HKEY_CURRENT_CONFIG");
44 LPCTSTR STR_HKEY_PERFORMANCE_DATA = _TEXT("HKEY_PERFORMANCE_DATA");
45
46
47 LPTSTR app_name = _TEXT("regnav");
48 LPCTSTR app_ver = _TEXT("1.0.4");
49 HANDLE CurrentWorkingKey = INVALID_HANDLE_VALUE; /* \ */
50 TCHAR CurrentPath [CURRENT_PATH_SIZE] = _TEXT("\\");
51 BOOL Done = FALSE;
52 INT LastExitCode = 0;
53
54
55 /* === COMMANDS === */
56
57 #define CMDPROTOIF (int argc,LPTSTR argv[])
58 typedef int (*CommandFunction) CMDPROTOIF;
59 #define CMDPROTO(n) int n CMDPROTOIF
60
61
62 typedef
63 struct _COMMAND_DESCRIPTOR
64 {
65 LPCTSTR Name;
66 LPCTSTR ShortDescription;
67 LPCTSTR Usage;
68 CommandFunction Command;
69 int MinArgc;
70 int MaxArgc;
71
72 } COMMAND_DESCRIPTOR, * PCOMMAND_DESCRIPTOR;
73
74
75 CMDPROTO(cmd_ck);
76 CMDPROTO(cmd_exit);
77 CMDPROTO(cmd_help);
78 CMDPROTO(cmd_ls);
79 CMDPROTO(cmd_pwk);
80 CMDPROTO(cmd_ver);
81
82
83 COMMAND_DESCRIPTOR
84 CommandsTable [] =
85 {
86 {
87 _TEXT("ck"),
88 _TEXT("Change the working key."),
89 _TEXT("CK key\n\nChange the working key."),
90 cmd_ck,
91 1,
92 2
93 },
94 {
95 _TEXT("exit"),
96 _TEXT("Terminate the application."),
97 _TEXT("EXIT\n\nTerminate the application."),
98 cmd_exit,
99 1,
100 1
101 },
102 {
103 _TEXT("help"),
104 _TEXT("Print this commands summary, or a command's synopsis."),
105 _TEXT("HELP [command]\n\nPrint commands summary, or a command's synopsis."),
106 cmd_help,
107 1,
108 2
109 },
110 {
111 _TEXT("ls"),
112 _TEXT("List a key's values and subkeys."),
113 _TEXT("LS [key]\n\nList a key's values and subkeys."),
114 cmd_ls,
115 1,
116 2
117 },
118 {
119 _TEXT("pwk"),
120 _TEXT("Print the current working key."),
121 _TEXT("PWK\n\nPrint the current working key."),
122 cmd_pwk,
123 1,
124 1
125 },
126 {
127 _TEXT("ver"),
128 _TEXT("Print version information."),
129 _TEXT("VER\n\nPrint version information."),
130 cmd_ver,
131 1,
132 1
133 },
134 /* End of array marker */
135 { NULL }
136 };
137
138
139 /* === CMD MANAGER === */
140
141
142 PCOMMAND_DESCRIPTOR
143 DecodeVerb( LPCTSTR Name )
144 {
145 register int i;
146
147 for ( i = 0;
148 CommandsTable[i].Name;
149 ++i
150 )
151 {
152 if (0 == lstrcmpi(CommandsTable[i].Name,Name))
153 {
154 return & CommandsTable[i];
155 }
156 }
157 return COMMAND_NOT_FOUND;
158 }
159
160 /* === Visual key name manager */
161
162 typedef
163 struct _SPLIT_KEY_NAME
164 {
165 TCHAR Host [32];
166 HANDLE Hive;
167 TCHAR SubKey [_MAX_PATH];
168
169 } SPLIT_KEY_NAME, * PSPLIT_KEY_NAME;
170
171
172 PSPLIT_KEY_NAME
173 ParseKeyName(
174 LPTSTR KeyName,
175 PSPLIT_KEY_NAME k
176 )
177 {
178 TCHAR *r = KeyName;
179 TCHAR *w = NULL;
180 TCHAR SystemKey [64];
181
182 assert(r && k);
183 ZeroMemory( k, sizeof (SPLIT_KEY_NAME) );
184 k->Hive = INVALID_HANDLE_VALUE;
185 /* HOST */
186 if (r[0] == _TEXT('\\') && r[1] == _TEXT('\\'))
187 {
188 for ( r += 2, w = k->Host;
189 (*r && (*r != _TEXT('\\')));
190 ++r
191 ) {
192 *w++ = *r;
193 }
194 if (w) *w = _TEXT('\0');
195 }
196 /* SYSTEM KEY */
197 if (*r == _TEXT('\\')) ++r;
198 for ( w = SystemKey;
199 (*r && (*r != _TEXT('\\')));
200 ++r
201 ) {
202 *w++ = *r;
203 }
204 if (w) *w = _TEXT('\0');
205 if (0 == lstrcmpi(STR_HKEY_CLASSES_ROOT, SystemKey))
206 {
207 k->Hive = HKEY_CLASSES_ROOT;
208 }
209 else if (0 == lstrcmpi(STR_HKEY_CURRENT_USER, SystemKey))
210 {
211 k->Hive = HKEY_CURRENT_USER;
212 }
213 else if (0 == lstrcmpi(STR_HKEY_LOCAL_MACHINE, SystemKey))
214 {
215 k->Hive = HKEY_LOCAL_MACHINE;
216 }
217 else if (0 == lstrcmpi(STR_HKEY_USERS, SystemKey))
218 {
219 k->Hive = HKEY_USERS;
220 }
221 else if (0 == lstrcmpi(STR_HKEY_CURRENT_CONFIG, SystemKey))
222 {
223 k->Hive = HKEY_CURRENT_CONFIG;
224 }
225 else if (0 == lstrcmpi(STR_HKEY_PERFORMANCE_DATA, SystemKey))
226 {
227 k->Hive = HKEY_PERFORMANCE_DATA;
228 }
229 /* SUBKEY */
230 if (*r == _TEXT('\\')) ++r;
231 for ( w = k->SubKey;
232 (*r);
233 ++r
234 ) {
235 *w++ = *r;
236 }
237 if (w) *w = _TEXT('\0');
238 /* OK */
239 return k;
240 }
241
242 /* === COMMANDS === */
243
244
245 /**********************************************************************
246 * ck
247 *
248 * DESCRIPTION
249 * Change the current working key.
250 */
251 CMDPROTO(cmd_ck)
252 {
253 LONG rv;
254 SPLIT_KEY_NAME k;
255
256 if (0 == lstrcmp(argv[1], _TEXT("..")))
257 {
258 _tprintf( _TEXT("Change to parent not implemented yet.\n") );
259 return EXIT_FAILURE;
260 }
261 if (INVALID_HANDLE_VALUE != CurrentWorkingKey)
262 {
263 RegCloseKey(CurrentWorkingKey);
264 CurrentWorkingKey = INVALID_HANDLE_VALUE;
265 }
266 if (NULL == ParseKeyName(argv[1], &k))
267 {
268 return EXIT_FAILURE;
269 }
270 rv = RegOpenKeyEx(
271 k.Hive, /* handle of open key */
272 k.SubKey, /* address of name of subkey to open */
273 0, /* reserved */
274 (REGSAM) KEY_ENUMERATE_SUB_KEYS,/* security access mask */
275 & CurrentWorkingKey /* address of handle of open key */
276 );
277 if (ERROR_SUCCESS != rv)
278 {
279 PrintWin32Error(L"RegOpenKeyEx",GetLastError());
280 return EXIT_FAILURE;
281 }
282 return EXIT_SUCCESS;
283 }
284
285
286 /**********************************************************************
287 * exit
288 *
289 * DESCRIPTION
290 * Terminate.
291 */
292 CMDPROTO(cmd_exit)
293 {
294 Done = TRUE;
295 _tprintf( _TEXT("Quitting...\n") );
296 return EXIT_SUCCESS;
297 }
298
299
300 /**********************************************************************
301 * help
302 *
303 * DESCRIPTION
304 * Print help.
305 */
306 CMDPROTO(cmd_help)
307 {
308 PCOMMAND_DESCRIPTOR cd = NULL;
309
310 if (1 == argc)
311 {
312 int CommandIndex;
313
314 for ( CommandIndex = 0;
315 (CommandsTable[CommandIndex].Name);
316 CommandIndex++
317 )
318 {
319 _tprintf(
320 _TEXT("%s\t%s\n"),
321 CommandsTable[CommandIndex].Name,
322 CommandsTable[CommandIndex].ShortDescription
323 );
324 }
325 return EXIT_SUCCESS;
326 }
327 if ((cd = DecodeVerb(argv[1])))
328 {
329 _tprintf(
330 _TEXT("%s\n"),
331 cd->Usage
332 );
333 return EXIT_SUCCESS;
334 }
335 _tprintf(
336 _TEXT("Unknown help item \"%s\".\n"),
337 argv[1]
338 );
339 return EXIT_FAILURE;
340 }
341
342
343 /**********************************************************************
344 * ls
345 *
346 * DESCRIPTION
347 * List a key.
348 */
349 CMDPROTO(cmd_ls)
350 {
351 LONG rv;
352 DWORD dwIndexK = 0;
353 DWORD dwIndexV = 0;
354 UCHAR Name [256];
355 DWORD cbName;
356 UCHAR Class [256];
357 DWORD cbClass;
358 UCHAR Data [1024];
359 DWORD cbData;
360 DWORD Type;
361 FILETIME ft;
362 SYSTEMTIME st;
363
364 /* _self is always present */
365 _tprintf( _TEXT(".\\\n") );
366 /* _root directory? */
367 if (INVALID_HANDLE_VALUE == CurrentWorkingKey)
368 {
369 _tprintf(
370 _TEXT("%s\\\n"),
371 STR_HKEY_CLASSES_ROOT
372 );
373 _tprintf(
374 _TEXT("%s\\\n"),
375 STR_HKEY_CURRENT_USER
376 );
377 _tprintf(
378 _TEXT("%s\\\n"),
379 STR_HKEY_LOCAL_MACHINE
380 );
381 _tprintf(
382 _TEXT("%s\\\n"),
383 STR_HKEY_USERS
384 );
385 _tprintf(
386 _TEXT("%s\\\n"),
387 STR_HKEY_CURRENT_CONFIG
388 );
389 _tprintf(
390 _TEXT("%s\\\n"),
391 STR_HKEY_PERFORMANCE_DATA
392 );
393 return EXIT_SUCCESS;
394 }
395 /* _parent is present only if _self != _root
396 * (FIXME: change it when RegConnect... available)
397 */
398 _tprintf( _TEXT("..\\\n") );
399 /* Enumerate subkeys of the current key. */
400 do {
401 cbName = sizeof(Name);
402 cbClass = sizeof(Class);
403 rv = RegEnumKeyEx(
404 CurrentWorkingKey, /* handle of key to enumerate */
405 dwIndexK, /* index of subkey to enumerate */
406 Name, /* address of buffer for subkey name */
407 & cbName, /* address for size of subkey buffer */
408 NULL, /* reserved */
409 Class, /* address of buffer for class string */
410 & cbClass, /* address for size of class buffer */
411 & ft /* address for time key last written to */
412 );
413 if (ERROR_SUCCESS == rv)
414 {
415 FileTimeToSystemTime( & ft, & st );
416 if (cbClass)
417 _tprintf(
418 _TEXT("%-32s\\ %4d-%02d-%02d %02d:%02d [%s]\n"),
419 Name,
420 st.wYear, st.wMonth, st.wDay,
421 st.wHour, st.wMinute,
422 Class
423 );
424 else
425 _tprintf(
426 _TEXT("%-32s\\ %4d-%02d-%02d %02d:%02d\n"),
427 Name,
428 st.wYear, st.wMonth, st.wDay,
429 st.wHour, st.wMinute
430 );
431 ++dwIndexK;
432 }
433 } while (ERROR_SUCCESS == rv);
434 /* Enumerate key's values */
435 do {
436 cbName = sizeof(Name);
437 cbData = sizeof(Data);
438 rv = RegEnumValue(
439 CurrentWorkingKey, /* handle of key to query */
440 dwIndexV, /* index of value to query */
441 Name, /* address of buffer for value string */
442 & cbName, /* address for size of value buffer */
443 NULL, /* reserved */
444 & Type, /* address of buffer for type code */
445 Data, /* address of buffer for value data */
446 & cbData /* address for size of data buffer */
447 );
448 if (ERROR_SUCCESS == rv)
449 {
450 switch (Type)
451 {
452 case REG_DWORD:
453 _tprintf(
454 _TEXT("%s = *REG_DWORD*\n"),
455 Name
456 );
457 break;
458 case REG_EXPAND_SZ:
459 /* expand env vars */
460 break;
461 case REG_LINK:
462 /* reparse! */
463 break;
464 case REG_SZ:
465 _tprintf(
466 _TEXT("%s = \"%s\"\n"),
467 Name,
468 Data
469 );
470 break;
471 }
472 ++dwIndexV;
473 }
474 } while (ERROR_SUCCESS == rv);
475 return (UINT) dwIndexK + (UINT) dwIndexV;
476 }
477
478
479 /**********************************************************************
480 * pwk
481 *
482 * DESCRIPTION
483 * Print the current working key.
484 */
485 CMDPROTO(cmd_pwk)
486 {
487 if (INVALID_HANDLE_VALUE == CurrentWorkingKey)
488 {
489 _tprintf( _TEXT("[\\]\n") );
490 return EXIT_SUCCESS;
491 }
492 _tprintf(
493 _TEXT("[%s]\n"),
494 CurrentPath
495 );
496 return EXIT_SUCCESS;
497 }
498
499
500 /**********************************************************************
501 * ver
502 *
503 * DESCRIPTION
504 * Print version information.
505 */
506 CMDPROTO(cmd_ver)
507 {
508 _tprintf(
509 _TEXT("\
510 %s version %s (compiled on %s, at %s)\n\
511 ReactOS Console Registry Navigator\n\
512 Copyright (c) 1998, 1999 Emanuele Aliberti\n\n"),
513 app_name,
514 app_ver,
515 _TEXT(__DATE__),
516 _TEXT(__TIME__)
517 );
518 return EXIT_SUCCESS;
519 }
520
521
522 /* === UTILITIES === */
523
524
525 #define ARGV_SIZE 32
526
527 INT
528 ParseCommandLine(
529 LPTSTR InputBuffer,
530 LPTSTR argv[]
531 )
532 {
533 register INT n = 0;
534 register TCHAR *c = InputBuffer;
535
536 assert(InputBuffer);
537 do
538 {
539 for ( ;
540 ( *c
541 && ( (*c == _TEXT(' '))
542 || (*c == _TEXT('\t'))
543 || (*c == _TEXT('\n'))
544 )
545 );
546 ++c
547 );
548 argv[n++] = c;
549 if (*c)
550 {
551 for ( ;
552 ( *c
553 && (*c != _TEXT(' '))
554 && (*c != _TEXT('\t'))
555 && (*c != _TEXT('\n'))
556 );
557 ++c
558 );
559 *c++ = _TEXT('\0');
560 }
561 } while ( *c );
562 return n;
563 }
564
565
566 VOID
567 DisplayPrompt(VOID)
568 {
569 _tprintf(
570 _TEXT("[%s] "),
571 CurrentPath
572 );
573 }
574
575
576 /* === MAIN === */
577
578
579 int
580 main(
581 int argc,
582 char * argv []
583 )
584 {
585 TCHAR InputBuffer [INPUT_BUFFER_SIZE];
586 PCOMMAND_DESCRIPTOR cd;
587 INT LocalArgc;
588 LPTSTR LocalArgv [ARGV_SIZE];
589
590
591 while (!Done)
592 {
593 DisplayPrompt();
594 _fgetts(
595 InputBuffer,
596 (sizeof InputBuffer / sizeof (TCHAR)),
597 stdin
598 );
599 if (0 == lstrlen(InputBuffer)) continue;
600 LocalArgc = ParseCommandLine(InputBuffer, LocalArgv);
601 if (LocalArgc && (cd = DecodeVerb(LocalArgv[0])))
602 {
603 if (LocalArgc < cd->MinArgc)
604 {
605 _tprintf(
606 _TEXT("Too few arguments. Type \"HELP %s\".\n"),
607 LocalArgv[0]
608 );
609 continue;
610 }
611 if (LocalArgc > cd->MaxArgc)
612 {
613 _tprintf(
614 _TEXT("Too many arguments. Type \"HELP %s\".\n"),
615 LocalArgv[0]
616 );
617 continue;
618 }
619 LastExitCode = cd->Command(
620 LocalArgc,
621 LocalArgv
622 );
623 continue;
624 }
625 _tprintf(
626 _TEXT("Unknown command (\"%s\").\n"),
627 LocalArgv[0]
628 );
629 }
630 return EXIT_SUCCESS;
631 }
632
633
634 /* EOF */