wine/programs/regapi/regapi.c
2000-12-24 19:55:09 +00:00

1114 lines
32 KiB
C

/*
* Command line Registry implementation
*
* Copyright 1999 Sylvain St-Germain
*
* Note: Please consult the README file for more information.
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <winreg.h>
#include <winerror.h>
#include <winnt.h>
#include <string.h>
/******************************************************************************
* Defines and consts
*/
#define IDENTICAL 0
#define COMMAND_COUNT 7
#define KEY_MAX_LEN 1024
#define STDIN_MAX_LEN 2048
/* Return values */
#define COMMAND_NOT_FOUND -1
#define SUCCESS 0
#define NOT_ENOUGH_MEMORY 1
#define KEY_VALUE_ALREADY_SET 2
#define COMMAND_NOT_SUPPORTED 3
/* Generic global */
static BOOL bForce = FALSE; /* Is set to TRUE when -force is
passed on the command line */
/* Globals used by the api setValue, queryValue */
static LPSTR currentKeyName = NULL;
static HKEY currentKeyClass = 0;
static HKEY currentKeyHandle = 0;
static BOOL bTheKeyIsOpen = FALSE;
/* Delimiters used to parse the "value"="data" pair for setValue*/
#define SET_VALUE_MAX_ARGS 2
/* Delimiters used to parse the "value" to query queryValue*/
#define QUERY_VALUE_MAX_ARGS 1
static const char *setValueDelim[SET_VALUE_MAX_ARGS] = {"=", ""};
static const char *queryValueDelim[QUERY_VALUE_MAX_ARGS] = {""};
/* Array used to extract the data type from a string in getDataType. */
typedef struct tagDataTypeMap
{
char mask[15];
DWORD dataType;
} dataTypeMap;
static const dataTypeMap typeMap[] =
{
{"hex:", REG_BINARY},/* could be REG_NONE (?) */
{"dword:", REG_DWORD},
{"hex(0):", REG_NONE},
{"hex(1):", REG_SZ},
{"hex(2):", REG_EXPAND_SZ},
{"hex(3):", REG_BINARY},
{"hex(4):", REG_DWORD},
{"hex(5):", REG_DWORD_BIG_ENDIAN},
{"hex(6):", REG_LINK},
{"hex(7):", REG_MULTI_SZ},
{"hex(8):", REG_RESOURCE_LIST},
{"hex(9):", REG_FULL_RESOURCE_DESCRIPTOR},
{"hex(10):", REG_RESOURCE_REQUIREMENTS_LIST},
{"hex(80000000):", 0x80000000},
{"hex(80000001):", 0x80000001},
{"hex(80000002):", 0x80000002},
{"hex(80000003):", 0x80000003},
{"hex(80000004):", 0x80000004},
{"hex(80000005):", 0x80000005},
{"hex(80000006):", 0x80000006},
{"hex(80000007):", 0x80000007},
{"hex(80000008):", 0x80000008},
{"hex(80000009):", 0x80000000},
{"hex(8000000a):", 0x8000000A}
};
const static int LAST_TYPE_MAP = sizeof(typeMap)/sizeof(dataTypeMap);
/*
* Forward declaration
*/
typedef void (*commandAPI)(LPSTR lpsLine);
static void doSetValue(LPSTR lpsLine);
static void doDeleteValue(LPSTR lpsLine);
static void doCreateKey(LPSTR lpsLine);
static void doDeleteKey(LPSTR lpsLine);
static void doQueryValue(LPSTR lpsLine);
static void doRegisterDLL(LPSTR lpsLine);
static void doUnregisterDLL(LPSTR lpsLine);
/*
* current supported api
*/
static const char* commandNames[COMMAND_COUNT] = {
"setValue",
"deleteValue",
"createKey",
"deleteKey",
"queryValue",
"registerDLL",
"unregisterDLL"
};
/*
* Pointers to processing entry points
*/
static const commandAPI commandAPIs[COMMAND_COUNT] = {
doSetValue,
doDeleteValue,
doCreateKey,
doDeleteKey,
doQueryValue,
doRegisterDLL,
doUnregisterDLL
};
/*
* This array controls the registry saving needs at the end of the process
*/
static const BOOL commandSaveRegistry[COMMAND_COUNT] = {
TRUE,
TRUE,
TRUE,
TRUE,
FALSE,
TRUE,
TRUE
};
/*
* Generic prototyes
*/
static DWORD getDataType(LPSTR *lpValue);
static LPSTR getRegKeyName(LPSTR lpLine);
static HKEY getRegClass(LPSTR lpLine);
static LPSTR getArg(LPSTR arg);
static INT getCommand(LPSTR commandName);
static DWORD convertHexToDWord(char *str, BYTE *buf);
static DWORD convertHexCSVToHex(char *str, BYTE *buf, ULONG bufLen);
static LPSTR convertHexToHexCSV( BYTE *buf, ULONG len);
static LPSTR convertHexToDWORDStr( BYTE *buf, ULONG len);
static HRESULT openKey(LPSTR stdInput);
static void closeKey();
/*
* api setValue prototypes
*/
static void processSetValue(LPSTR cmdline);
static HRESULT setValue(LPSTR *argv);
/*
* api queryValue prototypes
*/
static void processQueryValue(LPSTR cmdline);
/*
* Help Text displayed when invalid parameters are provided
*/
static char helpText[] =
"NAME\n"
" regapi - provide a command line interface to the wine registry.\n"
"\n"
"SYNOPSIS\n"
" regapi commandName [-force] < file\n"
"\n"
"DESCRIPTION\n"
" regapi allows editing the wine registry. It processes the given\n"
" commandName for every line in the stdin data stream. Input data\n"
" format may vary depending on the commandName see INPUT FILE FORMAT.\n"
"\n"
"OPTIONS\n"
" commandName\n"
" Instruct regapi about what action to perform on the data stream.\n"
" Currently, only setValue and queryValue are supported and\n"
" implemented.\n"
"\n"
" -force\n"
" When provided the action will be performed anyway. This may\n"
" have a different meaning depending on the context. For example,\n"
" when providing -force to setValue, the value is set even if it\n"
" was previously set to another value.\n"
"\n"
" < file\n"
" STDIN channel, provide a file name with line of the appropriate\n"
" format.\n"
"\n"
"INPUT FILE FORMAT\n"
"\n"
" setValue\n"
" The input file format required by the setValue command is similar\n"
" to the one obtained from regedit.exe export option. The only\n"
" difference is that multi line values are not supported, the\n"
" value data must be on a single line.\n"
"\n"
" [KEY_CLASS\\Some\\Path\\For\\A\\Key]\n"
" \"Value1\"=\"Data1\"\n"
" \"Value2\"=\"Data2\"\n"
" \"Valuen\"=\"Datan\"\n"
" ...\n"
"\n"
" queryValue\n"
" The input file format required by the queryValue command is\n"
" similar to the one required by setValue. The only\n"
" difference is that you only provide the value name.\n"
"\n"
" [KEY_CLASS\\Some\\Path\\For\\A\\Key]\n"
" \"Value1\"\n"
" \"Value2\"\n"
" \"Valuen\"\n"
" ...\n"
" registerDLL\n"
" The input file format is a list of DLLs to register\n"
"\n"
" unregisterDLL\n"
" The input file format is a list of DLLs to unregister\n"
" February 1999.\n"
;
/******************************************************************************
* This function returns the HKEY associated with the data type encoded in the
* value. It modifies the input parameter (key value) in order to skip this
* "now useless" data type information.
*/
DWORD getDataType(LPSTR *lpValue)
{
INT counter = 0;
DWORD dwReturn = REG_SZ;
for (; counter < LAST_TYPE_MAP; counter++)
{
LONG len = strlen(typeMap[counter].mask);
if ( strncasecmp( *lpValue, typeMap[counter].mask, len) == IDENTICAL)
{
/*
* We found it, modify the value's pointer in order to skip the data
* type identifier, set the return value and exit the loop.
*/
(*lpValue) += len;
dwReturn = typeMap[counter].dataType;
break;
}
}
return dwReturn;
}
/******************************************************************************
* Extracts from a [HKEY\some\key\path] type of line the key name (what starts
* after the first '\' and end before the ']'
*/
LPSTR getRegKeyName(LPSTR lpLine)
{
LPSTR keyNameBeg = NULL;
LPSTR keyNameEnd = NULL;
char lpLineCopy[KEY_MAX_LEN];
if (lpLine == NULL)
return NULL;
strcpy(lpLineCopy, lpLine);
keyNameBeg = strstr(lpLineCopy, "\\"); /* The key name start by '\' */
keyNameBeg++; /* but is not part of the key name */
keyNameEnd = strstr(lpLineCopy, "]"); /* The key name end by ']' */
*keyNameEnd = '\0'; /* Isolate the key name */
currentKeyName = HeapAlloc(GetProcessHeap(), 0, strlen(keyNameBeg)+1);
if (currentKeyName != NULL)
strcpy(currentKeyName, keyNameBeg);
return currentKeyName;
}
/******************************************************************************
* Extracts from a [HKEY/some/key/path] type of line the key class (what
* starts after the '[' and ends before the first '\'
*/
static HKEY getRegClass(LPSTR lpClass)
{
LPSTR classNameEnd;
LPSTR classNameBeg;
char lpClassCopy[KEY_MAX_LEN];
if (lpClass == NULL)
return (HKEY)ERROR_INVALID_PARAMETER;
strcpy(lpClassCopy, lpClass);
classNameEnd = strstr(lpClassCopy, "\\"); /* The class name end by '\' */
*classNameEnd = '\0'; /* Isolate the class name */
classNameBeg = &lpClassCopy[1]; /* Skip the '[' */
if (strcmp( classNameBeg, "HKEY_LOCAL_MACHINE") == IDENTICAL )
return HKEY_LOCAL_MACHINE;
else if (strcmp( classNameBeg, "HKEY_USERS") == IDENTICAL )
return HKEY_USERS;
else if (strcmp( classNameBeg, "HKEY_CLASSES_ROOT") == IDENTICAL )
return HKEY_CLASSES_ROOT;
else if (strcmp( classNameBeg, "HKEY_CURRENT_CONFIG") == IDENTICAL )
return HKEY_CURRENT_CONFIG;
else if (strcmp( classNameBeg, "HKEY_CURRENT_USER") == IDENTICAL )
return HKEY_CURRENT_USER;
else
return (HKEY)ERROR_INVALID_PARAMETER;
}
/******************************************************************************
* Returns an allocated buffer with a cleaned copy (removed the surrounding
* dbl quotes) of the passed value.
*/
static LPSTR getArg( LPSTR arg)
{
LPSTR tmp = NULL;
ULONG len;
if (arg == NULL)
return NULL;
/*
* Get rid of surrounding quotes
*/
len = strlen(arg);
if( arg[len-1] == '\"' ) arg[len-1] = '\0';
if( arg[0] == '\"' ) arg++;
tmp = HeapAlloc(GetProcessHeap(), 0, strlen(arg)+1);
strcpy(tmp, arg);
return tmp;
}
/******************************************************************************
* Returns the index in the commands array of the command to process.
*/
static INT getCommand(LPSTR commandName)
{
INT count;
for (count=0; count < COMMAND_COUNT; count++)
if ( strcmp(commandName, commandNames[count]) == IDENTICAL)
return count;
return COMMAND_NOT_FOUND;
}
/******************************************************************************
* Converts a hex representation of a DWORD into a DWORD.
*/
static DWORD convertHexToDWord(char *str, BYTE *buf)
{
char *s = str; /* Pointer to current */
char *b = buf; /* Pointer to result */
ULONG strPos = 0;
memset(buf, 0, 4);
while (strPos < 4) /* 8 byte in a DWORD */
{
char xbuf[3];
char wc;
memcpy(xbuf,s,2); xbuf[2]='\0';
sscanf(xbuf,"%02x",(UINT*)&wc);
*b++ =(unsigned char)wc;
s+=2;
strPos+=1;
}
return 4; /* always 4 byte for the word */
}
/******************************************************************************
* Converts a hex buffer into a hex comma separated values
*/
static char* convertHexToHexCSV(BYTE *buf, ULONG bufLen)
{
char* str;
char* ptrStr;
BYTE* ptrBuf;
ULONG current = 0;
str = HeapAlloc(GetProcessHeap(), 0, (bufLen+1)*2);
memset(str, 0, (bufLen+1)*2);
ptrStr = str; /* Pointer to result */
ptrBuf = buf; /* Pointer to current */
while (current < bufLen)
{
BYTE bCur = ptrBuf[current++];
char res[3];
sprintf(res, "%02x", (unsigned int)*&bCur);
strcat(str, res);
strcat(str, ",");
}
/* Get rid of the last comma */
str[strlen(str)-1] = '\0';
return str;
}
/******************************************************************************
* Converts a hex buffer into a DWORD string
*/
static char* convertHexToDWORDStr(BYTE *buf, ULONG bufLen)
{
char* str;
char* ptrStr;
BYTE* ptrBuf;
ULONG current = 0;
str = HeapAlloc(GetProcessHeap(), 0, (bufLen*2)+1);
memset(str, 0, (bufLen*2)+1);
ptrStr = str; /* Pointer to result */
ptrBuf = buf; /* Pointer to current */
while (current < bufLen)
{
BYTE bCur = ptrBuf[current++];
char res[3];
sprintf(res, "%02x", (unsigned int)*&bCur);
strcat(str, res);
}
/* Get rid of the last comma */
return str;
}
/******************************************************************************
* Converts a hex comma separated values list into a hex list.
*/
static DWORD convertHexCSVToHex(char *str, BYTE *buf, ULONG bufLen)
{
char *s = str; /* Pointer to current */
char *b = buf; /* Pointer to result */
ULONG strLen = strlen(str);
ULONG strPos = 0;
DWORD byteCount = 0;
memset(buf, 0, bufLen);
/*
* warn the user if we are here with a string longer than 2 bytes that does
* not contains ",". It is more likely because the data is invalid.
*/
if ( ( strlen(str) > 2) && ( strstr(str, ",") == NULL) )
printf("regapi: WARNING converting CSV hex stream with no comma, "
"input data seems invalid.\n");
while (strPos < strLen)
{
char xbuf[3];
char wc;
memcpy(xbuf,s,2); xbuf[3]='\0';
sscanf(xbuf,"%02x",(UINT*)&wc);
*b++ =(unsigned char)wc;
s+=3;
strPos+=3;
byteCount++;
}
return byteCount;
}
/******************************************************************************
* Sets the value in argv[0] to the data in argv[1] for the currently
* opened key.
*/
static HRESULT setValue(LPSTR *argv)
{
HRESULT hRes;
DWORD dwSize = KEY_MAX_LEN;
DWORD dwType = 0;
DWORD dwDataType;
LPSTR lpsCurrentValue;
LPSTR keyValue = argv[0];
LPSTR keyData = argv[1];
/* Make some checks */
if ( (keyValue == NULL) || (keyData == NULL) )
return ERROR_INVALID_PARAMETER;
lpsCurrentValue=HeapAlloc(GetProcessHeap(), 0,KEY_MAX_LEN);
/*
* Default registry values are encoded in the input stream as '@' but as
* blank in the wine registry.
*/
if( (keyValue[0] == '@') && (strlen(keyValue) == 1) )
keyValue[0] = '\0';
/* Get the data type stored into the value field */
dwDataType = getDataType(&keyData);
memset(lpsCurrentValue, 0, KEY_MAX_LEN);
hRes = RegQueryValueExA(
currentKeyHandle,
keyValue,
NULL,
&dwType,
(LPBYTE)lpsCurrentValue,
&dwSize);
while(hRes==ERROR_MORE_DATA){
dwSize+=KEY_MAX_LEN;
lpsCurrentValue=HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,lpsCurrentValue,dwSize);
hRes = RegQueryValueExA(currentKeyHandle,keyValue,NULL,&dwType,(LPBYTE)lpsCurrentValue,&dwSize);
}
if( ( strlen(lpsCurrentValue) == 0 ) || /* The value is not existing */
( bForce )) /* -force option */
{
LPBYTE lpbData;
BYTE convert[KEY_MAX_LEN];
DWORD dwLen;
if ( dwDataType == REG_SZ ) /* no convertion for string */
{
dwLen = strlen(keyData);
lpbData = keyData;
}
else if (dwDataType == REG_DWORD) /* Convert the dword types */
{
dwLen = convertHexToDWord(keyData, convert);
lpbData = convert;
}
else /* Convert the hexadecimal types */
{
dwLen = convertHexCSVToHex(keyData, convert, KEY_MAX_LEN);
lpbData = convert;
}
hRes = RegSetValueEx(
currentKeyHandle,
keyValue,
0, /* Reserved */
dwDataType,
lpbData,
dwLen);
}
else
{
/* return the current value data into argv[1] */
if (argv[1] != NULL)
{
HeapFree(GetProcessHeap(), 0, argv[1]);
argv[1] = HeapAlloc(GetProcessHeap(), 0, dwSize+1);
if ( argv[1] != NULL ) {
strncpy(argv[1], lpsCurrentValue, dwSize);
argv[1][dwSize]='\0';
}
}
return KEY_VALUE_ALREADY_SET;
}
return hRes;
}
/******************************************************************************
* Open the key
*/
static HRESULT openKey( LPSTR stdInput)
{
DWORD dwDisp;
HRESULT hRes;
/* Sanity checks */
if (stdInput == NULL)
return ERROR_INVALID_PARAMETER;
/* Get the registry class */
currentKeyClass = getRegClass(stdInput); /* Sets global variable */
if (currentKeyClass == (HKEY)ERROR_INVALID_PARAMETER)
return (HRESULT)ERROR_INVALID_PARAMETER;
/* Get the key name */
currentKeyName = getRegKeyName(stdInput); /* Sets global variable */
if (currentKeyName == NULL)
return ERROR_INVALID_PARAMETER;
hRes = RegCreateKeyEx(
currentKeyClass, /* Class */
currentKeyName, /* Sub Key */
0, /* MUST BE 0 */
NULL, /* object type */
REG_OPTION_NON_VOLATILE, /* option, REG_OPTION_NON_VOLATILE ... */
KEY_ALL_ACCESS, /* access mask, KEY_ALL_ACCESS */
NULL, /* security attribute */
&currentKeyHandle, /* result */
&dwDisp); /* disposition, REG_CREATED_NEW_KEY or
REG_OPENED_EXISTING_KEY */
if (hRes == ERROR_SUCCESS)
bTheKeyIsOpen = TRUE;
return hRes;
}
/******************************************************************************
* This function is a wrapper arround the setValue function. It prepares the
* land and clean the area once completed.
*/
static void processSetValue(LPSTR cmdline)
{
LPSTR argv[SET_VALUE_MAX_ARGS]; /* args storage */
LPSTR token = NULL; /* current token analized */
ULONG argCounter = 0; /* counter of args */
INT counter;
HRESULT hRes = 0;
/*
* Init storage and parse the line
*/
for (counter=0; counter<SET_VALUE_MAX_ARGS; counter++)
argv[counter]=NULL;
while( (token = strsep(&cmdline, setValueDelim[argCounter])) != NULL )
{
argv[argCounter++] = getArg(token);
if (argCounter == SET_VALUE_MAX_ARGS)
break; /* Stop processing args no matter what */
}
hRes = setValue(argv);
if ( hRes == ERROR_SUCCESS )
printf(
"regapi: Value \"%s\" has been set to \"%s\" in key [%s]\n",
argv[0],
argv[1],
currentKeyName);
else if ( hRes == KEY_VALUE_ALREADY_SET )
printf(
"regapi: Value \"%s\" already set to \"%s\" in key [%s]\n",
argv[0],
argv[1],
currentKeyName);
else
printf("regapi: ERROR Key %s not created. Value: %s, Data: %s\n",
currentKeyName,
argv[0],
argv[1]);
/*
* Do some cleanup
*/
for (counter=0; counter<argCounter; counter++)
if (argv[counter] != NULL)
HeapFree(GetProcessHeap(), 0, argv[counter]);
}
/******************************************************************************
* This function is a wrapper arround the queryValue function. It prepares the
* land and clean the area once completed.
*/
static void processQueryValue(LPSTR cmdline)
{
LPSTR argv[QUERY_VALUE_MAX_ARGS];/* args storage */
LPSTR token = NULL; /* current token analized */
ULONG argCounter = 0; /* counter of args */
INT counter;
HRESULT hRes = 0;
LPSTR keyValue = NULL;
LPSTR lpsRes = NULL;
/*
* Init storage and parse the line
*/
for (counter=0; counter<QUERY_VALUE_MAX_ARGS; counter++)
argv[counter]=NULL;
while( (token = strsep(&cmdline, queryValueDelim[argCounter])) != NULL )
{
argv[argCounter++] = getArg(token);
if (argCounter == QUERY_VALUE_MAX_ARGS)
break; /* Stop processing args no matter what */
}
/* The value we look for is the first token on the line */
if ( argv[0] == NULL )
return; /* SHOULD NOT OCCURS */
else
keyValue = argv[0];
if( (keyValue[0] == '@') && (strlen(keyValue) == 1) )
{
LONG lLen = KEY_MAX_LEN;
CHAR* lpsData=HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,KEY_MAX_LEN);
/*
* We need to query the key default value
*/
hRes = RegQueryValue(
currentKeyHandle,
currentKeyName,
(LPBYTE)lpsData,
&lLen);
if (hRes==ERROR_MORE_DATA) {
lpsData=HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,lpsData,lLen);
hRes = RegQueryValue(currentKeyHandle,currentKeyName,(LPBYTE)lpsData,&lLen);
}
if (hRes == ERROR_SUCCESS)
{
lpsRes = HeapAlloc( GetProcessHeap(), 0, lLen);
strncpy(lpsRes, lpsData, lLen);
lpsRes[lLen-1]='\0';
}
}
else
{
DWORD dwLen = KEY_MAX_LEN;
BYTE* lpbData=HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,KEY_MAX_LEN);
DWORD dwType;
/*
* We need to query a specific value for the key
*/
hRes = RegQueryValueEx(
currentKeyHandle,
keyValue,
0,
&dwType,
(LPBYTE)lpbData,
&dwLen);
if (hRes==ERROR_MORE_DATA) {
lpbData=HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,lpbData,dwLen);
hRes = RegQueryValueEx(currentKeyHandle,keyValue,NULL,&dwType,(LPBYTE)lpbData,&dwLen);
}
if (hRes == ERROR_SUCCESS)
{
/*
* Convert the returned data to a displayable format
*/
switch ( dwType )
{
case REG_SZ:
case REG_EXPAND_SZ:
{
lpsRes = HeapAlloc( GetProcessHeap(), 0, dwLen);
strncpy(lpsRes, lpbData, dwLen);
lpsRes[dwLen-1]='\0';
break;
}
case REG_DWORD:
{
lpsRes = convertHexToDWORDStr(lpbData, dwLen);
break;
}
default:
{
lpsRes = convertHexToHexCSV(lpbData, dwLen);
break;
}
}
}
HeapFree(GetProcessHeap(), 0, lpbData);
}
if ( hRes == ERROR_SUCCESS )
printf(
"regapi: Value \"%s\" = \"%s\" in key [%s]\n",
keyValue,
lpsRes,
currentKeyName);
else
printf("regapi: ERROR Value \"%s\" not found. for key \"%s\"\n",
keyValue,
currentKeyName);
/*
* Do some cleanup
*/
for (counter=0; counter<argCounter; counter++)
if (argv[counter] != NULL)
HeapFree(GetProcessHeap(), 0, argv[counter]);
if (lpsRes != NULL)
HeapFree(GetProcessHeap(), 0, lpsRes);
}
/******************************************************************************
* Close the currently opened key.
*/
static void closeKey()
{
RegCloseKey(currentKeyHandle);
HeapFree(GetProcessHeap(), 0, currentKeyName); /* Allocated by getKeyName */
bTheKeyIsOpen = FALSE;
currentKeyName = NULL;
currentKeyClass = 0;
currentKeyHandle = 0;
}
/******************************************************************************
* This funtion is the main entry point to the setValue type of action. It
* receives the currently read line and dispatch the work depending on the
* context.
*/
static void doSetValue(LPSTR stdInput)
{
/*
* We encoutered the end of the file, make sure we
* close the opened key and exit
*/
if (stdInput == NULL)
{
if (bTheKeyIsOpen != FALSE)
closeKey();
return;
}
if ( stdInput[0] == '[') /* We are reading a new key */
{
if ( bTheKeyIsOpen != FALSE )
closeKey(); /* Close the previous key before */
if ( openKey(stdInput) != ERROR_SUCCESS )
printf ("regapi: doSetValue failed to open key %s\n", stdInput);
}
else if( ( bTheKeyIsOpen ) &&
(( stdInput[0] == '@') || /* reading a default @=data pair */
( stdInput[0] == '\"'))) /* reading a new value=data pair */
{
processSetValue(stdInput);
}
else /* since we are assuming that the */
{ /* file format is valid we must */
if ( bTheKeyIsOpen ) /* be reading a blank line which */
closeKey(); /* indicate end of this key processing */
}
}
/******************************************************************************
* This funtion is the main entry point to the queryValue type of action. It
* receives the currently read line and dispatch the work depending on the
* context.
*/
static void doQueryValue(LPSTR stdInput) {
/*
* We encoutered the end of the file, make sure we
* close the opened key and exit
*/
if (stdInput == NULL)
{
if (bTheKeyIsOpen != FALSE)
closeKey();
return;
}
if ( stdInput[0] == '[') /* We are reading a new key */
{
if ( bTheKeyIsOpen != FALSE )
closeKey(); /* Close the previous key before */
if ( openKey(stdInput) != ERROR_SUCCESS )
printf ("regapi: doSetValue failed to open key %s\n", stdInput);
}
else if( ( bTheKeyIsOpen ) &&
(( stdInput[0] == '@') || /* reading a default @=data pair */
( stdInput[0] == '\"'))) /* reading a new value=data pair */
{
processQueryValue(stdInput);
}
else /* since we are assuming that the */
{ /* file format is valid we must */
if ( bTheKeyIsOpen ) /* be reading a blank line which */
closeKey(); /* indicate end of this key processing */
}
}
/******************************************************************************
* This funtion is the main entry point to the deletetValue type of action. It
* receives the currently read line and dispatch the work depending on the
* context.
*/
static void doDeleteValue(LPSTR line) {
printf ("regapi: deleteValue not yet implemented\n");
}
/******************************************************************************
* This funtion is the main entry point to the deleteKey type of action. It
* receives the currently read line and dispatch the work depending on the
* context.
*/
static void doDeleteKey(LPSTR line) {
printf ("regapi: deleteKey not yet implemented\n");
}
/******************************************************************************
* This funtion is the main entry point to the createKey type of action. It
* receives the currently read line and dispatch the work depending on the
* context.
*/
static void doCreateKey(LPSTR line) {
printf ("regapi: createKey not yet implemented\n");
}
/******************************************************************************
* This funtion is the main entry point to the registerDLL action. It
* receives the currently read line, then loads and registers the requested DLLs
*/
static void doRegisterDLL(LPSTR stdInput) {
HMODULE theLib = 0;
UINT retVal = 0;
/* Check for valid input */
if (stdInput == NULL)
return;
/* Load and register the library, then free it */
theLib = LoadLibrary(stdInput);
if (theLib)
{
FARPROC lpfnDLLRegProc = GetProcAddress(theLib, "DllRegisterServer");
if (lpfnDLLRegProc)
retVal = (*lpfnDLLRegProc)();
else
printf("regapi: Couldn't find DllRegisterServer proc in '%s'.\n", stdInput);
if (retVal != S_OK)
printf("regapi: DLLRegisterServer error 0x%x in '%s'.\n", retVal, stdInput);
FreeLibrary(theLib);
}
else
{
printf("regapi: Could not load DLL '%s'.\n", stdInput);
}
}
/******************************************************************************
* This funtion is the main entry point to the unregisterDLL action. It
* receives the currently read line, then loads and unregisters the requested DLLs
*/
static void doUnregisterDLL(LPSTR stdInput) {
HMODULE theLib = 0;
UINT retVal = 0;
/* Check for valid input */
if (stdInput == NULL)
return;
/* Load and unregister the library, then free it */
theLib = LoadLibrary(stdInput);
if (theLib)
{
FARPROC lpfnDLLRegProc = GetProcAddress(theLib, "DllUnregisterServer");
if (lpfnDLLRegProc)
retVal = (*lpfnDLLRegProc)();
else
printf("regapi: Couldn't find DllUnregisterServer proc in '%s'.\n", stdInput);
if (retVal != S_OK)
printf("regapi: DLLUnregisterServer error 0x%x in '%s'.\n", retVal, stdInput);
FreeLibrary(theLib);
}
else
{
printf("regapi: Could not load DLL '%s'.\n", stdInput);
}
}
/******************************************************************************
* MAIN - The main simply validate the first parameter (command to perform)
* It then read the STDIN lines by lines forwarding their processing
* to the appropriate method.
*/
int PASCAL WinMain (HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show)
{
LPSTR token = NULL; /* current token analized */
LPSTR stdInput = NULL; /* line read from stdin */
INT cmdIndex = -1; /* index of the command in array */
LPSTR nextLine = NULL;
ULONG currentSize = STDIN_MAX_LEN;
stdInput = HeapAlloc(GetProcessHeap(), 0, STDIN_MAX_LEN);
nextLine = HeapAlloc(GetProcessHeap(), 0, STDIN_MAX_LEN);
if (stdInput == NULL || nextLine== NULL)
return NOT_ENOUGH_MEMORY;
/*
* get the command, should be the first arg (modify cmdLine)
*/
token = strsep(&cmdline, " ");
if (token != NULL)
{
cmdIndex = getCommand(token);
if (cmdIndex == COMMAND_NOT_FOUND)
{
printf("regapi: Command \"%s\" is not supported.\n", token);
printf(helpText);
return COMMAND_NOT_SUPPORTED;
}
}
else
{
printf(
"regapi: The first item on the command line must be the command name.\n");
printf(helpText);
return COMMAND_NOT_SUPPORTED;
}
/*
* check to see weather we force the action
* (meaning differ depending on the command performed)
*/
if ( cmdline != NULL ) /* will be NULL if '-force' is not provided */
if ( strstr(cmdline, "-force") != NULL )
bForce = TRUE;
printf("Processing stdin...\n");
while ( TRUE )
{
/*
* read a line
*/
ULONG curSize=STDIN_MAX_LEN;
char* s=NULL;
while((NULL!=(stdInput=fgets(stdInput,curSize,stdin))) && (NULL==(s=strchr(stdInput,'\n'))) ){
fseek(stdin,-curSize,SEEK_CUR+1);
stdInput=HeapReAlloc(GetProcessHeap(), 0,stdInput,curSize+=STDIN_MAX_LEN);
}
/*
* Make some handy generic stuff here...
*/
if ( stdInput != NULL )
{
stdInput[strlen(stdInput) -1] = '\0'; /* get rid of new line */
if( stdInput[0] == '#' ) /* this is a comment, skip */
continue;
while( stdInput[strlen(stdInput) -1] == '\\' ){ /* a '\' char in the end of the current line means */
/* that this line is not complete and we have to get */
stdInput[strlen(stdInput) -1]= '\0'; /* the rest in the next lines */
nextLine = fgets(nextLine, STDIN_MAX_LEN, stdin);
nextLine[strlen(nextLine)-1] = '\0';
if ( (strlen(stdInput)+strlen(nextLine)) > currentSize){
stdInput=HeapReAlloc(GetProcessHeap(),0,stdInput,strlen(stdInput)+STDIN_MAX_LEN);
currentSize+=STDIN_MAX_LEN;
}
strcat(stdInput,nextLine+2);
}
}
/*
* We process every lines even the NULL (last) line, to indicate the
* end of the processing to the specific process.
*/
commandAPIs[cmdIndex](stdInput);
if (stdInput == NULL) /* EOF encountered */
break;
}
#if 0
/*
* Save the registry only if it was modified
*/
if ( commandSaveRegistry[cmdIndex] != FALSE )
SHELL_SaveRegistry();
#endif
HeapFree(GetProcessHeap(), 0, nextLine);
HeapFree(GetProcessHeap(), 0, stdInput);
return SUCCESS;
}