2 * Command line Registry implementation
4 * Copyright 1999 Sylvain St-Germain
6 * Note: Please consult the README file for more information.
18 /******************************************************************************
22 #define COMMAND_COUNT 7
24 #define KEY_MAX_LEN 1024
25 #define STDIN_MAX_LEN 2048
28 #define COMMAND_NOT_FOUND -1
30 #define NOT_ENOUGH_MEMORY 1
31 #define KEY_VALUE_ALREADY_SET 2
32 #define COMMAND_NOT_SUPPORTED 3
35 static BOOL bForce = FALSE; /* Is set to TRUE when -force is
36 passed on the command line */
38 /* Globals used by the api setValue, queryValue */
39 static LPSTR currentKeyName = NULL;
40 static HKEY currentKeyClass = 0;
41 static HKEY currentKeyHandle = 0;
42 static BOOL bTheKeyIsOpen = FALSE;
44 /* Delimiters used to parse the "value"="data" pair for setValue*/
45 #define SET_VALUE_MAX_ARGS 2
46 /* Delimiters used to parse the "value" to query queryValue*/
47 #define QUERY_VALUE_MAX_ARGS 1
49 static const char *setValueDelim[SET_VALUE_MAX_ARGS] = {"=", ""};
50 static const char *queryValueDelim[QUERY_VALUE_MAX_ARGS] = {""};
56 typedef void (*commandAPI)(LPSTR lpsLine);
58 static void doSetValue(LPSTR lpsLine);
59 static void doDeleteValue(LPSTR lpsLine);
60 static void doCreateKey(LPSTR lpsLine);
61 static void doDeleteKey(LPSTR lpsLine);
62 static void doQueryValue(LPSTR lpsLine);
63 static void doRegisterDLL(LPSTR lpsLine);
64 static void doUnregisterDLL(LPSTR lpsLine);
67 * Currently supported api
69 static const char* commandNames[COMMAND_COUNT] = {
80 * Pointers to processing entry points
82 static const commandAPI commandAPIs[COMMAND_COUNT] = {
93 * This array controls the registry saving needs at the end of the process
95 static const BOOL commandSaveRegistry[COMMAND_COUNT] = {
108 static DWORD getDataType(LPSTR *lpValue, DWORD* parse_type);
109 static LPSTR getRegKeyName(LPSTR lpLine);
110 static HKEY getRegClass(LPSTR lpLine);
111 static LPSTR getArg(LPSTR arg);
112 static INT getCommand(LPSTR commandName);
113 static DWORD convertHexToDWord(char *str, BYTE *buf);
114 static DWORD convertHexCSVToHex(char *str, BYTE *buf, ULONG bufLen);
115 static LPSTR convertHexToHexCSV( BYTE *buf, ULONG len);
116 static LPSTR convertHexToDWORDStr( BYTE *buf, ULONG len);
117 static HRESULT openKey(LPSTR stdInput);
118 static void closeKey();
121 * api setValue prototypes
123 static void processSetValue(LPSTR cmdline);
124 static HRESULT setValue(LPSTR *argv);
127 * api queryValue prototypes
129 static void processQueryValue(LPSTR cmdline);
132 * Help Text displayed when invalid parameters are provided
134 static char helpText[] =
136 " regapi - perform certain actions on the wine registry.\n"
139 " regapi commandName [-force] < file\n"
142 " regapi modifies settings in the wine registry. It processes\n"
143 " the given commandName for every line in the stdin data stream.\n"
144 " Input data format may vary depending on the commandName\n"
145 " (see INPUT FILE FORMAT).\n"
149 " Instruct regapi about what action to perform on the data stream.\n"
150 " Currently, only setValue and queryValue are supported and\n"
154 " When provided the action will be performed anyway. This may\n"
155 " have a different meaning depending on the context. For example,\n"
156 " when providing -force to setValue, the value is set even if it\n"
157 " was previously set to another value.\n"
160 " STDIN channel, provide a file name with line of the appropriate\n"
163 "INPUT FILE FORMAT\n"
166 " The input file format required by the setValue command is similar\n"
167 " to the one obtained from regedit.exe export option. The only\n"
168 " difference is that multi line values are not supported, the\n"
169 " value data must be on a single line.\n"
171 " [KEY_CLASS\\Some\\Path\\For\\A\\Key]\n"
172 " \"Value1\"=\"Data1\"\n"
173 " \"Value2\"=\"Data2\"\n"
174 " \"Valuen\"=\"Datan\"\n"
178 " The input file format required by the queryValue command is\n"
179 " similar to the one required by setValue. The only\n"
180 " difference is that you only provide the value name.\n"
182 " [KEY_CLASS\\Some\\Path\\For\\A\\Key]\n"
188 " The input file format is a list of DLLs to register\n"
191 " The input file format is a list of DLLs to unregister\n"
196 /******************************************************************************
197 * This function returns the HKEY associated with the data type encoded in the
198 * value. It modifies the input parameter (key value) in order to skip this
199 * "now useless" data type information.
201 * Note: Updated based on the algorithm used in 'server/registry.c'
203 DWORD getDataType(LPSTR *lpValue, DWORD* parse_type)
205 struct data_type { const char *tag; int len; int type; int parse_type; };
207 static const struct data_type data_types[] =
208 { /* actual type */ /* type to assume for parsing */
209 { "\"", 1, REG_SZ, REG_SZ },
210 { "str:\"", 5, REG_SZ, REG_SZ },
211 { "str(2):\"", 8, REG_EXPAND_SZ, REG_SZ },
212 { "str(7):\"", 8, REG_MULTI_SZ, REG_SZ },
213 { "hex:", 4, REG_BINARY, REG_BINARY },
214 { "dword:", 6, REG_DWORD, REG_DWORD },
215 { "hex(", 4, -1, REG_BINARY },
219 const struct data_type *ptr;
222 for (ptr = data_types; ptr->tag; ptr++)
224 if (memcmp( ptr->tag, *lpValue, ptr->len ))
228 *parse_type = ptr->parse_type;
233 /* "hex(xx):" is special */
235 type = (int)strtoul( *lpValue , &end, 16 );
236 if (**lpValue=='\0' || *end!=')' || *(end+1)!=':') {
244 return (**lpValue=='\0'?REG_SZ:REG_NONE);
247 /******************************************************************************
248 * Extracts from a [HKEY\some\key\path] type of line the key name (what starts
249 * after the first '\' and end before the ']'
251 LPSTR getRegKeyName(LPSTR lpLine)
253 LPSTR keyNameBeg = NULL;
254 LPSTR keyNameEnd = NULL;
255 char lpLineCopy[KEY_MAX_LEN];
260 strcpy(lpLineCopy, lpLine);
262 keyNameBeg = strstr(lpLineCopy, "\\"); /* The key name start by '\' */
263 keyNameBeg++; /* but is not part of the key name */
264 keyNameEnd = strstr(lpLineCopy, "]"); /* The key name end by ']' */
265 *keyNameEnd = '\0'; /* Isolate the key name */
267 currentKeyName = HeapAlloc(GetProcessHeap(), 0, strlen(keyNameBeg)+1);
268 if (currentKeyName != NULL)
269 strcpy(currentKeyName, keyNameBeg);
271 return currentKeyName;
274 /******************************************************************************
275 * Extracts from a [HKEY/some/key/path] type of line the key class (what
276 * starts after the '[' and ends before the first '\'
278 static HKEY getRegClass(LPSTR lpClass)
283 char lpClassCopy[KEY_MAX_LEN];
286 return (HKEY)ERROR_INVALID_PARAMETER;
288 strcpy(lpClassCopy, lpClass);
290 classNameEnd = strstr(lpClassCopy, "\\"); /* The class name end by '\' */
291 *classNameEnd = '\0'; /* Isolate the class name */
292 classNameBeg = &lpClassCopy[1]; /* Skip the '[' */
294 if (strcmp( classNameBeg, "HKEY_LOCAL_MACHINE") == IDENTICAL )
295 return HKEY_LOCAL_MACHINE;
296 else if (strcmp( classNameBeg, "HKEY_USERS") == IDENTICAL )
298 else if (strcmp( classNameBeg, "HKEY_CLASSES_ROOT") == IDENTICAL )
299 return HKEY_CLASSES_ROOT;
300 else if (strcmp( classNameBeg, "HKEY_CURRENT_CONFIG") == IDENTICAL )
301 return HKEY_CURRENT_CONFIG;
302 else if (strcmp( classNameBeg, "HKEY_CURRENT_USER") == IDENTICAL )
303 return HKEY_CURRENT_USER;
305 return (HKEY)ERROR_INVALID_PARAMETER;
308 /******************************************************************************
309 * This is a replacement for strsep which is not portable (missing on Solaris).
311 static char* getToken(char** str, const char* delims)
321 while (**str!='\0') {
322 if (strchr(delims,**str)!=NULL) {
329 /* There is no other token */
334 /******************************************************************************
335 * Returns an allocated buffer with a cleaned copy (removed the surrounding
336 * dbl quotes) of the passed value.
338 static LPSTR getArg( LPSTR arg)
347 * Get rid of surrounding quotes
351 if( arg[len-1] == '\"' ) arg[len-1] = '\0';
352 if( arg[0] == '\"' ) arg++;
354 tmp = HeapAlloc(GetProcessHeap(), 0, strlen(arg)+1);
360 /******************************************************************************
361 * Returns the index in the commands array of the command to process.
363 static INT getCommand(LPSTR commandName)
366 for (count=0; count < COMMAND_COUNT; count++)
367 if ( strcmp(commandName, commandNames[count]) == IDENTICAL)
370 return COMMAND_NOT_FOUND;
373 /******************************************************************************
374 * Converts a hex representation of a DWORD into a DWORD.
376 static DWORD convertHexToDWord(char *str, BYTE *buf)
383 sscanf(xbuf,"%08lx",&dw);
384 memcpy(buf,&dw,sizeof(DWORD));
385 return sizeof(DWORD);
388 /******************************************************************************
389 * Converts a hex buffer into a hex comma separated values
391 static char* convertHexToHexCSV(BYTE *buf, ULONG bufLen)
399 str = HeapAlloc(GetProcessHeap(), 0, (bufLen+1)*2);
400 memset(str, 0, (bufLen+1)*2);
401 ptrStr = str; /* Pointer to result */
402 ptrBuf = buf; /* Pointer to current */
404 while (current < bufLen)
406 BYTE bCur = ptrBuf[current++];
409 sprintf(res, "%02x", (unsigned int)*&bCur);
414 /* Get rid of the last comma */
415 str[strlen(str)-1] = '\0';
419 /******************************************************************************
420 * Converts a hex buffer into a DWORD string
422 static char* convertHexToDWORDStr(BYTE *buf, ULONG bufLen)
427 if ( bufLen != sizeof(DWORD) ) return NULL;
429 str = HeapAlloc(GetProcessHeap(), 0, (bufLen*2)+1);
431 memcpy(&dw,buf,sizeof(DWORD));
432 sprintf(str, "%08lx", dw);
434 /* Get rid of the last comma */
437 /******************************************************************************
438 * Converts a hex comma separated values list into a hex list.
440 static DWORD convertHexCSVToHex(char *str, BYTE *buf, ULONG bufLen)
442 char *s = str; /* Pointer to current */
443 char *b = buf; /* Pointer to result */
445 ULONG strLen = strlen(str);
449 memset(buf, 0, bufLen);
452 * warn the user if we are here with a string longer than 2 bytes that does
453 * not contains ",". It is more likely because the data is invalid.
455 if ( ( strlen(str) > 2) && ( strstr(str, ",") == NULL) )
456 printf("regapi: WARNING converting CSV hex stream with no comma, "
457 "input data seems invalid.\n");
459 while (strPos < strLen)
464 memcpy(xbuf,s,2); xbuf[3]='\0';
465 sscanf(xbuf,"%02x",(UINT*)&wc);
466 *b++ =(unsigned char)wc;
477 /******************************************************************************
478 * Sets the value in argv[0] to the data in argv[1] for the currently
481 static HRESULT setValue(LPSTR *argv)
484 DWORD dwSize = KEY_MAX_LEN;
486 DWORD dwDataType,dwParseType;
488 LPSTR lpsCurrentValue;
490 LPSTR keyValue = getArg(argv[0]);
491 LPSTR keyData = argv[1];
493 /* Make some checks */
494 if ( (keyValue == NULL) || (keyData == NULL) )
495 return ERROR_INVALID_PARAMETER;
497 lpsCurrentValue=HeapAlloc(GetProcessHeap(), 0,KEY_MAX_LEN);
499 * Default registry values are encoded in the input stream as '@' but as
500 * blank in the wine registry.
502 if( (keyValue[0] == '@') && (strlen(keyValue) == 1) )
505 /* Get the data type stored into the value field */
506 dwDataType = getDataType(&keyData,&dwParseType);
508 memset(lpsCurrentValue, 0, KEY_MAX_LEN);
509 hRes = RegQueryValueExA(
514 (LPBYTE)lpsCurrentValue,
517 while(hRes==ERROR_MORE_DATA){
519 lpsCurrentValue=HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,lpsCurrentValue,dwSize);
520 hRes = RegQueryValueExA(currentKeyHandle,keyValue,NULL,&dwType,(LPBYTE)lpsCurrentValue,&dwSize);
523 if( ( strlen(lpsCurrentValue) == 0 ) || /* The value is not existing */
524 ( bForce )) /* -force option */
527 BYTE convert[KEY_MAX_LEN];
530 if ( dwParseType == REG_SZ) /* no conversion for string */
532 dwLen = strlen(keyData);
533 if (dwLen>0 && keyData[dwLen-1]=='"')
540 else if (dwParseType == REG_DWORD) /* Convert the dword types */
542 dwLen = convertHexToDWord(keyData, convert);
545 else /* Convert the hexadecimal types */
547 dwLen = convertHexCSVToHex(keyData, convert, KEY_MAX_LEN);
551 hRes = RegSetValueEx(
561 /* return the current value data into argv[1] */
564 HeapFree(GetProcessHeap(), 0, argv[1]);
565 argv[1] = HeapAlloc(GetProcessHeap(), 0, dwSize+1);
567 if ( argv[1] != NULL ) {
568 strncpy(argv[1], lpsCurrentValue, dwSize);
569 argv[1][dwSize]='\0';
573 hRes=KEY_VALUE_ALREADY_SET;
575 if (keyValue != NULL)
576 HeapFree(GetProcessHeap(), 0, keyValue);
581 /******************************************************************************
584 static HRESULT openKey( LPSTR stdInput)
590 if (stdInput == NULL)
591 return ERROR_INVALID_PARAMETER;
593 /* Get the registry class */
594 currentKeyClass = getRegClass(stdInput); /* Sets global variable */
595 if (currentKeyClass == (HKEY)ERROR_INVALID_PARAMETER)
596 return (HRESULT)ERROR_INVALID_PARAMETER;
598 /* Get the key name */
599 currentKeyName = getRegKeyName(stdInput); /* Sets global variable */
600 if (currentKeyName == NULL)
601 return ERROR_INVALID_PARAMETER;
603 hRes = RegCreateKeyEx(
604 currentKeyClass, /* Class */
605 currentKeyName, /* Sub Key */
607 NULL, /* object type */
608 REG_OPTION_NON_VOLATILE, /* option, REG_OPTION_NON_VOLATILE ... */
609 KEY_ALL_ACCESS, /* access mask, KEY_ALL_ACCESS */
610 NULL, /* security attribute */
611 ¤tKeyHandle, /* result */
612 &dwDisp); /* disposition, REG_CREATED_NEW_KEY or
613 REG_OPENED_EXISTING_KEY */
615 if (hRes == ERROR_SUCCESS)
616 bTheKeyIsOpen = TRUE;
621 /******************************************************************************
622 * This function is a wrapper for the setValue function. It prepares the
623 * land and clean the area once completed.
625 static void processSetValue(LPSTR cmdline)
627 LPSTR argv[SET_VALUE_MAX_ARGS]; /* args storage */
629 LPSTR token = NULL; /* current token analized */
630 ULONG argCounter = 0; /* counter of args */
635 * Init storage and parse the line
637 for (counter=0; counter<SET_VALUE_MAX_ARGS; counter++)
640 while( (token = getToken(&cmdline, setValueDelim[argCounter])) != NULL )
642 argv[argCounter++] = token;
644 if (argCounter == SET_VALUE_MAX_ARGS)
645 break; /* Stop processing args no matter what */
648 hRes = setValue(argv);
649 if ( hRes == ERROR_SUCCESS )
651 "regapi: Value \"%s\" has been set to \"%s\" in key [%s]\n",
656 else if ( hRes == KEY_VALUE_ALREADY_SET )
658 "regapi: Value \"%s\" already set to \"%s\" in key [%s]\n",
664 printf("regapi: ERROR Key %s not created. Value: %s, Data: %s\n",
670 /******************************************************************************
671 * This function is a wrapper for the queryValue function. It prepares the
672 * land and clean the area once completed.
674 static void processQueryValue(LPSTR cmdline)
676 LPSTR argv[QUERY_VALUE_MAX_ARGS];/* args storage */
677 LPSTR token = NULL; /* current token analized */
678 ULONG argCounter = 0; /* counter of args */
681 LPSTR keyValue = NULL;
685 * Init storage and parse the line
687 for (counter=0; counter<QUERY_VALUE_MAX_ARGS; counter++)
690 while( (token = getToken(&cmdline, queryValueDelim[argCounter])) != NULL )
692 argv[argCounter++] = getArg(token);
694 if (argCounter == QUERY_VALUE_MAX_ARGS)
695 break; /* Stop processing args no matter what */
698 /* The value we look for is the first token on the line */
699 if ( argv[0] == NULL )
700 return; /* SHOULD NOT HAPPEN */
704 if( (keyValue[0] == '@') && (strlen(keyValue) == 1) )
706 LONG lLen = KEY_MAX_LEN;
707 CHAR* lpsData=HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,KEY_MAX_LEN);
709 * We need to query the key default value
711 hRes = RegQueryValue(
717 if (hRes==ERROR_MORE_DATA) {
718 lpsData=HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,lpsData,lLen);
719 hRes = RegQueryValue(currentKeyHandle,currentKeyName,(LPBYTE)lpsData,&lLen);
722 if (hRes == ERROR_SUCCESS)
724 lpsRes = HeapAlloc( GetProcessHeap(), 0, lLen);
725 strncpy(lpsRes, lpsData, lLen);
731 DWORD dwLen = KEY_MAX_LEN;
732 BYTE* lpbData=HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,KEY_MAX_LEN);
735 * We need to query a specific value for the key
737 hRes = RegQueryValueEx(
745 if (hRes==ERROR_MORE_DATA) {
746 lpbData=HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,lpbData,dwLen);
747 hRes = RegQueryValueEx(currentKeyHandle,keyValue,NULL,&dwType,(LPBYTE)lpbData,&dwLen);
750 if (hRes == ERROR_SUCCESS)
753 * Convert the returned data to a displayable format
760 lpsRes = HeapAlloc( GetProcessHeap(), 0, dwLen);
761 strncpy(lpsRes, lpbData, dwLen);
762 lpsRes[dwLen-1]='\0';
767 lpsRes = convertHexToDWORDStr(lpbData, dwLen);
772 lpsRes = convertHexToHexCSV(lpbData, dwLen);
778 HeapFree(GetProcessHeap(), 0, lpbData);
782 if ( hRes == ERROR_SUCCESS )
784 "regapi: Value \"%s\" = \"%s\" in key [%s]\n",
790 printf("regapi: ERROR Value \"%s\" not found. for key \"%s\"\n",
797 for (counter=0; counter<argCounter; counter++)
798 if (argv[counter] != NULL)
799 HeapFree(GetProcessHeap(), 0, argv[counter]);
802 HeapFree(GetProcessHeap(), 0, lpsRes);
806 /******************************************************************************
807 * Close the currently opened key.
809 static void closeKey()
811 RegCloseKey(currentKeyHandle);
813 HeapFree(GetProcessHeap(), 0, currentKeyName); /* Allocated by getKeyName */
815 bTheKeyIsOpen = FALSE;
817 currentKeyName = NULL;
819 currentKeyHandle = 0;
822 /******************************************************************************
823 * This funtion is the main entry point to the setValue type of action. It
824 * receives the currently read line and dispatch the work depending on the
827 static void doSetValue(LPSTR stdInput)
830 * We encoutered the end of the file, make sure we
831 * close the opened key and exit
833 if (stdInput == NULL)
835 if (bTheKeyIsOpen != FALSE)
841 if ( stdInput[0] == '[') /* We are reading a new key */
843 if ( bTheKeyIsOpen != FALSE )
844 closeKey(); /* Close the previous key before */
846 if ( openKey(stdInput) != ERROR_SUCCESS )
847 printf ("regapi: doSetValue failed to open key %s\n", stdInput);
849 else if( ( bTheKeyIsOpen ) &&
850 (( stdInput[0] == '@') || /* reading a default @=data pair */
851 ( stdInput[0] == '\"'))) /* reading a new value=data pair */
853 processSetValue(stdInput);
855 else /* since we are assuming that the */
856 { /* file format is valid we must */
857 if ( bTheKeyIsOpen ) /* be reading a blank line which */
858 closeKey(); /* indicate end of this key processing */
862 /******************************************************************************
863 * This funtion is the main entry point to the queryValue type of action. It
864 * receives the currently read line and dispatch the work depending on the
867 static void doQueryValue(LPSTR stdInput) {
869 * We encoutered the end of the file, make sure we
870 * close the opened key and exit
872 if (stdInput == NULL)
874 if (bTheKeyIsOpen != FALSE)
880 if ( stdInput[0] == '[') /* We are reading a new key */
882 if ( bTheKeyIsOpen != FALSE )
883 closeKey(); /* Close the previous key before */
885 if ( openKey(stdInput) != ERROR_SUCCESS )
886 printf ("regapi: doSetValue failed to open key %s\n", stdInput);
888 else if( ( bTheKeyIsOpen ) &&
889 (( stdInput[0] == '@') || /* reading a default @=data pair */
890 ( stdInput[0] == '\"'))) /* reading a new value=data pair */
892 processQueryValue(stdInput);
894 else /* since we are assuming that the */
895 { /* file format is valid we must */
896 if ( bTheKeyIsOpen ) /* be reading a blank line which */
897 closeKey(); /* indicate end of this key processing */
901 /******************************************************************************
902 * This funtion is the main entry point to the deletetValue type of action. It
903 * receives the currently read line and dispatch the work depending on the
906 static void doDeleteValue(LPSTR line) {
907 printf ("regapi: deleteValue not yet implemented\n");
909 /******************************************************************************
910 * This funtion is the main entry point to the deleteKey type of action. It
911 * receives the currently read line and dispatch the work depending on the
914 static void doDeleteKey(LPSTR line) {
915 printf ("regapi: deleteKey not yet implemented\n");
917 /******************************************************************************
918 * This funtion is the main entry point to the createKey type of action. It
919 * receives the currently read line and dispatch the work depending on the
922 static void doCreateKey(LPSTR line) {
923 printf ("regapi: createKey not yet implemented\n");
926 /******************************************************************************
927 * This funtion is the main entry point to the registerDLL action. It
928 * receives the currently read line, then loads and registers the requested DLLs
930 static void doRegisterDLL(LPSTR stdInput) {
934 /* Check for valid input */
935 if (stdInput == NULL)
938 /* Load and register the library, then free it */
939 theLib = LoadLibrary(stdInput);
942 FARPROC lpfnDLLRegProc = GetProcAddress(theLib, "DllRegisterServer");
944 retVal = (*lpfnDLLRegProc)();
946 printf("regapi: Couldn't find DllRegisterServer proc in '%s'.\n", stdInput);
949 printf("regapi: DLLRegisterServer error 0x%x in '%s'.\n", retVal, stdInput);
955 printf("regapi: Could not load DLL '%s'.\n", stdInput);
959 /******************************************************************************
960 * This funtion is the main entry point to the unregisterDLL action. It
961 * receives the currently read line, then loads and unregisters the requested DLLs
963 static void doUnregisterDLL(LPSTR stdInput) {
967 /* Check for valid input */
968 if (stdInput == NULL)
971 /* Load and unregister the library, then free it */
972 theLib = LoadLibrary(stdInput);
975 FARPROC lpfnDLLRegProc = GetProcAddress(theLib, "DllUnregisterServer");
977 retVal = (*lpfnDLLRegProc)();
979 printf("regapi: Couldn't find DllUnregisterServer proc in '%s'.\n", stdInput);
982 printf("regapi: DLLUnregisterServer error 0x%x in '%s'.\n", retVal, stdInput);
988 printf("regapi: Could not load DLL '%s'.\n", stdInput);
992 /******************************************************************************
993 * MAIN - WinMain simply validates the first parameter (command to perform)
994 * It then reads the STDIN line by line forwarding their processing
995 * to the appropriate method.
997 int PASCAL WinMain (HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show)
999 LPSTR token = NULL; /* current token analized */
1000 LPSTR stdInput = NULL; /* line read from stdin */
1001 INT cmdIndex = -1; /* index of the command in array */
1002 LPSTR nextLine = NULL;
1003 ULONG currentSize = STDIN_MAX_LEN;
1005 stdInput = HeapAlloc(GetProcessHeap(), 0, STDIN_MAX_LEN);
1006 nextLine = HeapAlloc(GetProcessHeap(), 0, STDIN_MAX_LEN);
1008 if (stdInput == NULL || nextLine== NULL)
1009 return NOT_ENOUGH_MEMORY;
1012 * get the command, should be the first arg (modify cmdLine)
1014 token = getToken(&cmdline, " ");
1017 cmdIndex = getCommand(token);
1018 if (cmdIndex == COMMAND_NOT_FOUND)
1020 printf("regapi: Command \"%s\" is not supported.\n", token);
1022 return COMMAND_NOT_SUPPORTED;
1028 "regapi: The first item on the command line must be the command name.\n");
1030 return COMMAND_NOT_SUPPORTED;
1034 * check to see wether we force the action
1035 * (meaning differs depending on the command performed)
1037 if ( cmdline != NULL ) /* will be NULL if '-force' is not provided */
1038 if ( strstr(cmdline, "-force") != NULL )
1041 printf("Processing stdin...\n");
1048 ULONG curSize=STDIN_MAX_LEN;
1051 while((NULL!=(stdInput=fgets(stdInput,curSize,stdin))) && (NULL==(s=strchr(stdInput,'\n'))) ){
1052 fseek(stdin,-curSize,SEEK_CUR+1);
1053 stdInput=HeapReAlloc(GetProcessHeap(), 0,stdInput,curSize+=STDIN_MAX_LEN);
1056 * Make some handy generic stuff here...
1058 if ( stdInput != NULL )
1060 stdInput[strlen(stdInput) -1] = '\0'; /* get rid of new line */
1062 if( stdInput[0] == '#' ) /* this is a comment, skip */
1065 while( stdInput[strlen(stdInput) -1] == '\\' ){ /* a '\' char in the end of the current line means */
1066 /* that this line is not complete and we have to get */
1067 stdInput[strlen(stdInput) -1]= '\0'; /* the rest in the next lines */
1069 nextLine = fgets(nextLine, STDIN_MAX_LEN, stdin);
1071 nextLine[strlen(nextLine)-1] = '\0';
1073 if ( (strlen(stdInput)+strlen(nextLine)) > currentSize){
1075 stdInput=HeapReAlloc(GetProcessHeap(),0,stdInput,strlen(stdInput)+STDIN_MAX_LEN);
1077 currentSize+=STDIN_MAX_LEN;
1080 strcat(stdInput,nextLine+2);
1085 * We process every lines even the NULL (last) line, to indicate the
1086 * end of the processing to the specific process.
1088 commandAPIs[cmdIndex](stdInput);
1090 if (stdInput == NULL) /* EOF encountered */
1096 * Save the registry only if it was modified
1098 if ( commandSaveRegistry[cmdIndex] != FALSE )
1099 SHELL_SaveRegistry();
1101 HeapFree(GetProcessHeap(), 0, nextLine);
1103 HeapFree(GetProcessHeap(), 0, stdInput);