mirror of
https://github.com/reactos/reactos.git
synced 2024-08-16 16:39:08 +00:00
636 lines
12 KiB
C
636 lines
12 KiB
C
/* $Id: regnav.c,v 1.4 2000/09/11 20:17:02 ea Exp $
|
|
*
|
|
* regnav.c
|
|
*
|
|
* Copyright (c) 1998-2000 Emanuele Aliberti
|
|
*
|
|
* --------------------------------------------------------------------
|
|
*
|
|
* This software is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Library General Public License as
|
|
* published by the Free Software Foundation; either version 2 of the
|
|
* License, or (at your option) any later version.
|
|
*
|
|
* This software 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
|
|
* Library General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Library General Public
|
|
* License along with this software; see the file COPYING.LIB. If
|
|
* not, write to the Free Software Foundation, Inc., 675 Mass Ave,
|
|
* Cambridge, MA 02139, USA.
|
|
*
|
|
* --------------------------------------------------------------------
|
|
* ReactOS system registry console navigation tool.
|
|
*/
|
|
//#define UNICODE
|
|
#include <windows.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <tchar.h>
|
|
#include <assert.h>
|
|
#include "win32err.h"
|
|
|
|
#define INPUT_BUFFER_SIZE 512
|
|
#define COMMAND_NOT_FOUND NULL
|
|
#define CURRENT_PATH_SIZE 1024
|
|
|
|
LPCTSTR STR_HKEY_CLASSES_ROOT = _TEXT("HKEY_CLASSES_ROOT");
|
|
LPCTSTR STR_HKEY_CURRENT_USER = _TEXT("HKEY_CURRENT_USER");
|
|
LPCTSTR STR_HKEY_LOCAL_MACHINE = _TEXT("HKEY_LOCAL_MACHINE");
|
|
LPCTSTR STR_HKEY_USERS = _TEXT("HKEY_USERS");
|
|
LPCTSTR STR_HKEY_CURRENT_CONFIG = _TEXT("HKEY_CURRENT_CONFIG");
|
|
LPCTSTR STR_HKEY_PERFORMANCE_DATA = _TEXT("HKEY_PERFORMANCE_DATA");
|
|
|
|
|
|
LPTSTR app_name = _TEXT("regnav");
|
|
LPCTSTR app_ver = _TEXT("1.0.5");
|
|
HANDLE CurrentWorkingKey = INVALID_HANDLE_VALUE; /* \ */
|
|
TCHAR CurrentPath [CURRENT_PATH_SIZE] = _TEXT("\\");
|
|
BOOL Done = FALSE;
|
|
INT LastExitCode = 0;
|
|
|
|
|
|
/* === COMMANDS === */
|
|
|
|
#define CMDPROTOIF (int argc,LPTSTR argv[])
|
|
typedef int (*CommandFunction) CMDPROTOIF;
|
|
#define CMDPROTO(n) int n CMDPROTOIF
|
|
|
|
|
|
typedef
|
|
struct _COMMAND_DESCRIPTOR
|
|
{
|
|
LPCTSTR Name;
|
|
LPCTSTR ShortDescription;
|
|
LPCTSTR Usage;
|
|
CommandFunction Command;
|
|
int MinArgc;
|
|
int MaxArgc;
|
|
|
|
} COMMAND_DESCRIPTOR, * PCOMMAND_DESCRIPTOR;
|
|
|
|
|
|
CMDPROTO(cmd_ck);
|
|
CMDPROTO(cmd_exit);
|
|
CMDPROTO(cmd_help);
|
|
CMDPROTO(cmd_ls);
|
|
CMDPROTO(cmd_pwk);
|
|
CMDPROTO(cmd_ver);
|
|
|
|
|
|
COMMAND_DESCRIPTOR
|
|
CommandsTable [] =
|
|
{
|
|
{
|
|
_TEXT("ck"),
|
|
_TEXT("Change the working key."),
|
|
_TEXT("CK key\n\nChange the working key."),
|
|
cmd_ck,
|
|
1,
|
|
2
|
|
},
|
|
{
|
|
_TEXT("exit"),
|
|
_TEXT("Terminate the application."),
|
|
_TEXT("EXIT\n\nTerminate the application."),
|
|
cmd_exit,
|
|
1,
|
|
1
|
|
},
|
|
{
|
|
_TEXT("help"),
|
|
_TEXT("Print this commands summary, or a command's synopsis."),
|
|
_TEXT("HELP [command]\n\nPrint commands summary, or a command's synopsis."),
|
|
cmd_help,
|
|
1,
|
|
2
|
|
},
|
|
{
|
|
_TEXT("ls"),
|
|
_TEXT("List a key's values and subkeys."),
|
|
_TEXT("LS [key]\n\nList a key's values and subkeys."),
|
|
cmd_ls,
|
|
1,
|
|
2
|
|
},
|
|
{
|
|
_TEXT("pwk"),
|
|
_TEXT("Print the current working key."),
|
|
_TEXT("PWK\n\nPrint the current working key."),
|
|
cmd_pwk,
|
|
1,
|
|
1
|
|
},
|
|
{
|
|
_TEXT("ver"),
|
|
_TEXT("Print version information."),
|
|
_TEXT("VER\n\nPrint version information."),
|
|
cmd_ver,
|
|
1,
|
|
1
|
|
},
|
|
/* End of array marker */
|
|
{ NULL }
|
|
};
|
|
|
|
|
|
/* === CMD MANAGER === */
|
|
|
|
|
|
PCOMMAND_DESCRIPTOR
|
|
DecodeVerb( LPCTSTR Name )
|
|
{
|
|
register int i;
|
|
|
|
for ( i = 0;
|
|
CommandsTable[i].Name;
|
|
++i
|
|
)
|
|
{
|
|
if (0 == lstrcmpi(CommandsTable[i].Name,Name))
|
|
{
|
|
return & CommandsTable[i];
|
|
}
|
|
}
|
|
return COMMAND_NOT_FOUND;
|
|
}
|
|
|
|
/* === Visual key name manager */
|
|
|
|
typedef
|
|
struct _SPLIT_KEY_NAME
|
|
{
|
|
TCHAR Host [32];
|
|
HANDLE Hive;
|
|
TCHAR SubKey [_MAX_PATH];
|
|
|
|
} SPLIT_KEY_NAME, * PSPLIT_KEY_NAME;
|
|
|
|
|
|
PSPLIT_KEY_NAME
|
|
ParseKeyName(
|
|
LPTSTR KeyName,
|
|
PSPLIT_KEY_NAME k
|
|
)
|
|
{
|
|
TCHAR *r = KeyName;
|
|
TCHAR *w = NULL;
|
|
TCHAR SystemKey [64];
|
|
|
|
assert(r && k);
|
|
ZeroMemory( k, sizeof (SPLIT_KEY_NAME) );
|
|
k->Hive = INVALID_HANDLE_VALUE;
|
|
/* HOST */
|
|
if (r[0] == _TEXT('\\') && r[1] == _TEXT('\\'))
|
|
{
|
|
for ( r += 2, w = k->Host;
|
|
(*r && (*r != _TEXT('\\')));
|
|
++r
|
|
) {
|
|
*w++ = *r;
|
|
}
|
|
if (w) *w = _TEXT('\0');
|
|
}
|
|
/* SYSTEM KEY */
|
|
if (*r == _TEXT('\\')) ++r;
|
|
for ( w = SystemKey;
|
|
(*r && (*r != _TEXT('\\')));
|
|
++r
|
|
) {
|
|
*w++ = *r;
|
|
}
|
|
if (w) *w = _TEXT('\0');
|
|
if (0 == lstrcmpi(STR_HKEY_CLASSES_ROOT, SystemKey))
|
|
{
|
|
k->Hive = HKEY_CLASSES_ROOT;
|
|
}
|
|
else if (0 == lstrcmpi(STR_HKEY_CURRENT_USER, SystemKey))
|
|
{
|
|
k->Hive = HKEY_CURRENT_USER;
|
|
}
|
|
else if (0 == lstrcmpi(STR_HKEY_LOCAL_MACHINE, SystemKey))
|
|
{
|
|
k->Hive = HKEY_LOCAL_MACHINE;
|
|
}
|
|
else if (0 == lstrcmpi(STR_HKEY_USERS, SystemKey))
|
|
{
|
|
k->Hive = HKEY_USERS;
|
|
}
|
|
else if (0 == lstrcmpi(STR_HKEY_CURRENT_CONFIG, SystemKey))
|
|
{
|
|
k->Hive = HKEY_CURRENT_CONFIG;
|
|
}
|
|
else if (0 == lstrcmpi(STR_HKEY_PERFORMANCE_DATA, SystemKey))
|
|
{
|
|
k->Hive = HKEY_PERFORMANCE_DATA;
|
|
}
|
|
/* SUBKEY */
|
|
if (*r == _TEXT('\\')) ++r;
|
|
for ( w = k->SubKey;
|
|
(*r);
|
|
++r
|
|
) {
|
|
*w++ = *r;
|
|
}
|
|
if (w) *w = _TEXT('\0');
|
|
/* OK */
|
|
return k;
|
|
}
|
|
|
|
/* === COMMANDS === */
|
|
|
|
|
|
/**********************************************************************
|
|
* ck
|
|
*
|
|
* DESCRIPTION
|
|
* Change the current working key.
|
|
*/
|
|
CMDPROTO(cmd_ck)
|
|
{
|
|
LONG rv;
|
|
SPLIT_KEY_NAME k;
|
|
|
|
if (0 == lstrcmp(argv[1], _TEXT("..")))
|
|
{
|
|
_tprintf( _TEXT("Change to parent not implemented yet.\n") );
|
|
return EXIT_FAILURE;
|
|
}
|
|
if (INVALID_HANDLE_VALUE != CurrentWorkingKey)
|
|
{
|
|
RegCloseKey(CurrentWorkingKey);
|
|
CurrentWorkingKey = INVALID_HANDLE_VALUE;
|
|
}
|
|
if (NULL == ParseKeyName(argv[1], &k))
|
|
{
|
|
return EXIT_FAILURE;
|
|
}
|
|
rv = RegOpenKeyEx(
|
|
k.Hive, /* handle of open key */
|
|
k.SubKey, /* address of name of subkey to open */
|
|
0, /* reserved */
|
|
(REGSAM) KEY_ENUMERATE_SUB_KEYS,/* security access mask */
|
|
& CurrentWorkingKey /* address of handle of open key */
|
|
);
|
|
if (ERROR_SUCCESS != rv)
|
|
{
|
|
PrintWin32Error(L"RegOpenKeyEx",GetLastError());
|
|
return EXIT_FAILURE;
|
|
}
|
|
return EXIT_SUCCESS;
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
* exit
|
|
*
|
|
* DESCRIPTION
|
|
* Terminate.
|
|
*/
|
|
CMDPROTO(cmd_exit)
|
|
{
|
|
Done = TRUE;
|
|
_tprintf( _TEXT("Quitting...\n") );
|
|
return EXIT_SUCCESS;
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
* help
|
|
*
|
|
* DESCRIPTION
|
|
* Print help.
|
|
*/
|
|
CMDPROTO(cmd_help)
|
|
{
|
|
PCOMMAND_DESCRIPTOR cd = NULL;
|
|
|
|
if (1 == argc)
|
|
{
|
|
int CommandIndex;
|
|
|
|
for ( CommandIndex = 0;
|
|
(CommandsTable[CommandIndex].Name);
|
|
CommandIndex++
|
|
)
|
|
{
|
|
_tprintf(
|
|
_TEXT("%s\t%s\n"),
|
|
CommandsTable[CommandIndex].Name,
|
|
CommandsTable[CommandIndex].ShortDescription
|
|
);
|
|
}
|
|
return EXIT_SUCCESS;
|
|
}
|
|
if ((cd = DecodeVerb(argv[1])))
|
|
{
|
|
_tprintf(
|
|
_TEXT("%s\n"),
|
|
cd->Usage
|
|
);
|
|
return EXIT_SUCCESS;
|
|
}
|
|
_tprintf(
|
|
_TEXT("Unknown help item \"%s\".\n"),
|
|
argv[1]
|
|
);
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
* ls
|
|
*
|
|
* DESCRIPTION
|
|
* List a key.
|
|
*/
|
|
CMDPROTO(cmd_ls)
|
|
{
|
|
LONG rv;
|
|
DWORD dwIndexK = 0;
|
|
DWORD dwIndexV = 0;
|
|
UCHAR Name [256];
|
|
DWORD cbName;
|
|
UCHAR Class [256];
|
|
DWORD cbClass;
|
|
UCHAR Data [1024];
|
|
DWORD cbData;
|
|
DWORD Type;
|
|
FILETIME ft;
|
|
SYSTEMTIME st;
|
|
|
|
/* _self is always present */
|
|
_tprintf( _TEXT(".\\\n") );
|
|
/* _root directory? */
|
|
if (INVALID_HANDLE_VALUE == CurrentWorkingKey)
|
|
{
|
|
_tprintf(
|
|
_TEXT("%s\\\n"),
|
|
STR_HKEY_CLASSES_ROOT
|
|
);
|
|
_tprintf(
|
|
_TEXT("%s\\\n"),
|
|
STR_HKEY_CURRENT_USER
|
|
);
|
|
_tprintf(
|
|
_TEXT("%s\\\n"),
|
|
STR_HKEY_LOCAL_MACHINE
|
|
);
|
|
_tprintf(
|
|
_TEXT("%s\\\n"),
|
|
STR_HKEY_USERS
|
|
);
|
|
_tprintf(
|
|
_TEXT("%s\\\n"),
|
|
STR_HKEY_CURRENT_CONFIG
|
|
);
|
|
_tprintf(
|
|
_TEXT("%s\\\n"),
|
|
STR_HKEY_PERFORMANCE_DATA
|
|
);
|
|
return EXIT_SUCCESS;
|
|
}
|
|
/* _parent is present only if _self != _root
|
|
* (FIXME: change it when RegConnect... available)
|
|
*/
|
|
_tprintf( _TEXT("..\\\n") );
|
|
/* Enumerate subkeys of the current key. */
|
|
do {
|
|
cbName = sizeof(Name);
|
|
cbClass = sizeof(Class);
|
|
rv = RegEnumKeyEx(
|
|
CurrentWorkingKey, /* handle of key to enumerate */
|
|
dwIndexK, /* index of subkey to enumerate */
|
|
Name, /* address of buffer for subkey name */
|
|
& cbName, /* address for size of subkey buffer */
|
|
NULL, /* reserved */
|
|
Class, /* address of buffer for class string */
|
|
& cbClass, /* address for size of class buffer */
|
|
& ft /* address for time key last written to */
|
|
);
|
|
if (ERROR_SUCCESS == rv)
|
|
{
|
|
FileTimeToSystemTime( & ft, & st );
|
|
if (cbClass)
|
|
_tprintf(
|
|
_TEXT("%-32s\\ %4d-%02d-%02d %02d:%02d [%s]\n"),
|
|
Name,
|
|
st.wYear, st.wMonth, st.wDay,
|
|
st.wHour, st.wMinute,
|
|
Class
|
|
);
|
|
else
|
|
_tprintf(
|
|
_TEXT("%-32s\\ %4d-%02d-%02d %02d:%02d\n"),
|
|
Name,
|
|
st.wYear, st.wMonth, st.wDay,
|
|
st.wHour, st.wMinute
|
|
);
|
|
++dwIndexK;
|
|
}
|
|
} while (ERROR_SUCCESS == rv);
|
|
/* Enumerate key's values */
|
|
do {
|
|
cbName = sizeof(Name);
|
|
cbData = sizeof(Data);
|
|
rv = RegEnumValue(
|
|
CurrentWorkingKey, /* handle of key to query */
|
|
dwIndexV, /* index of value to query */
|
|
Name, /* address of buffer for value string */
|
|
& cbName, /* address for size of value buffer */
|
|
NULL, /* reserved */
|
|
& Type, /* address of buffer for type code */
|
|
Data, /* address of buffer for value data */
|
|
& cbData /* address for size of data buffer */
|
|
);
|
|
if (ERROR_SUCCESS == rv)
|
|
{
|
|
switch (Type)
|
|
{
|
|
case REG_DWORD:
|
|
_tprintf(
|
|
_TEXT("%s = *REG_DWORD*\n"),
|
|
Name
|
|
);
|
|
break;
|
|
case REG_EXPAND_SZ:
|
|
/* expand env vars */
|
|
break;
|
|
case REG_LINK:
|
|
/* reparse! */
|
|
break;
|
|
case REG_SZ:
|
|
_tprintf(
|
|
_TEXT("%s = \"%s\"\n"),
|
|
Name,
|
|
Data
|
|
);
|
|
break;
|
|
}
|
|
++dwIndexV;
|
|
}
|
|
} while (ERROR_SUCCESS == rv);
|
|
return (UINT) dwIndexK + (UINT) dwIndexV;
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
* pwk
|
|
*
|
|
* DESCRIPTION
|
|
* Print the current working key.
|
|
*/
|
|
CMDPROTO(cmd_pwk)
|
|
{
|
|
if (INVALID_HANDLE_VALUE == CurrentWorkingKey)
|
|
{
|
|
_tprintf( _TEXT("[\\]\n") );
|
|
return EXIT_SUCCESS;
|
|
}
|
|
_tprintf(
|
|
_TEXT("[%s]\n"),
|
|
CurrentPath
|
|
);
|
|
return EXIT_SUCCESS;
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
* ver
|
|
*
|
|
* DESCRIPTION
|
|
* Print version information.
|
|
*/
|
|
CMDPROTO(cmd_ver)
|
|
{
|
|
_tprintf(
|
|
_TEXT("\
|
|
%s version %s (compiled on %s, at %s)\n\
|
|
ReactOS Console Registry Navigator\n\
|
|
Copyright (c) 1998-2000 Emanuele Aliberti\n\n"),
|
|
app_name,
|
|
app_ver,
|
|
_TEXT(__DATE__),
|
|
_TEXT(__TIME__)
|
|
);
|
|
return EXIT_SUCCESS;
|
|
}
|
|
|
|
|
|
/* === UTILITIES === */
|
|
|
|
|
|
#define ARGV_SIZE 32
|
|
|
|
INT
|
|
ParseCommandLine(
|
|
LPTSTR InputBuffer,
|
|
LPTSTR argv[]
|
|
)
|
|
{
|
|
register INT n = 0;
|
|
register TCHAR *c = InputBuffer;
|
|
|
|
assert(InputBuffer);
|
|
do
|
|
{
|
|
for ( ;
|
|
( *c
|
|
&& ( (*c == _TEXT(' '))
|
|
|| (*c == _TEXT('\t'))
|
|
|| (*c == _TEXT('\n'))
|
|
)
|
|
);
|
|
++c
|
|
);
|
|
argv[n++] = c;
|
|
if (*c)
|
|
{
|
|
for ( ;
|
|
( *c
|
|
&& (*c != _TEXT(' '))
|
|
&& (*c != _TEXT('\t'))
|
|
&& (*c != _TEXT('\n'))
|
|
);
|
|
++c
|
|
);
|
|
*c++ = _TEXT('\0');
|
|
}
|
|
} while ( *c );
|
|
return n;
|
|
}
|
|
|
|
|
|
VOID
|
|
DisplayPrompt(VOID)
|
|
{
|
|
_tprintf(
|
|
_TEXT("[%s] "),
|
|
CurrentPath
|
|
);
|
|
}
|
|
|
|
|
|
/* === MAIN === */
|
|
|
|
|
|
int
|
|
main(
|
|
int argc,
|
|
char * argv []
|
|
)
|
|
{
|
|
TCHAR InputBuffer [INPUT_BUFFER_SIZE];
|
|
PCOMMAND_DESCRIPTOR cd;
|
|
INT LocalArgc;
|
|
LPTSTR LocalArgv [ARGV_SIZE];
|
|
|
|
|
|
while (!Done)
|
|
{
|
|
DisplayPrompt();
|
|
_fgetts(
|
|
InputBuffer,
|
|
(sizeof InputBuffer / sizeof (TCHAR)),
|
|
stdin
|
|
);
|
|
if (0 == lstrlen(InputBuffer)) continue;
|
|
LocalArgc = ParseCommandLine(InputBuffer, LocalArgv);
|
|
if (LocalArgc && (cd = DecodeVerb(LocalArgv[0])))
|
|
{
|
|
if (LocalArgc < cd->MinArgc)
|
|
{
|
|
_tprintf(
|
|
_TEXT("Too few arguments. Type \"HELP %s\".\n"),
|
|
LocalArgv[0]
|
|
);
|
|
continue;
|
|
}
|
|
if (LocalArgc > cd->MaxArgc)
|
|
{
|
|
_tprintf(
|
|
_TEXT("Too many arguments. Type \"HELP %s\".\n"),
|
|
LocalArgv[0]
|
|
);
|
|
continue;
|
|
}
|
|
LastExitCode = cd->Command(
|
|
LocalArgc,
|
|
LocalArgv
|
|
);
|
|
continue;
|
|
}
|
|
_tprintf(
|
|
_TEXT("Unknown command (\"%s\").\n"),
|
|
LocalArgv[0]
|
|
);
|
|
}
|
|
return EXIT_SUCCESS;
|
|
}
|
|
|
|
|
|
/* EOF */
|