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