Bug fixes.
[wine.git] / programs / regapi / regapi.c
blobb72fdf166cedf3f700259e6fc317c51a3d742a93
1 /*
2 * Command line Registry implementation
4 * Copyright 1999 Sylvain St-Germain
6 * Note: Please consult the README file for more information.
8 */
10 #include <stdio.h>
11 #include <malloc.h>
12 #include <windows.h>
13 #include <winreg.h>
14 #include <winerror.h>
15 #include <winnt.h>
16 #include <string.h>
17 #include <shell.h>
19 /******************************************************************************
20 * Defines and consts
22 #define IDENTICAL 0
23 #define COMMAND_COUNT 5
25 #define KEY_MAX_LEN 1024
26 #define STDIN_MAX_LEN 2048
28 /* Return values */
29 #define COMMAND_NOT_FOUND -1
30 #define SUCCESS 0
31 #define NOT_ENOUGH_MEMORY 1
32 #define KEY_VALUE_ALREADY_SET 2
33 #define COMMAND_NOT_SUPPORTED 3
35 /* Generic global */
36 static BOOL bForce = FALSE; /* Is set to TRUE when -force is
37 passed on the command line */
39 /* Globals used by the api setValue, queryValue */
40 static LPSTR currentKeyName = NULL;
41 static HKEY currentKeyClass = NULL;
42 static HKEY currentKeyHandle = NULL;
43 static BOOL bTheKeyIsOpen = FALSE;
45 /* Delimitors used to parse the "value"="data" pair for setValue*/
46 #define SET_VALUE_MAX_ARGS 2
47 /* Delimitors used to parse the "value" to query queryValue*/
48 #define QUERY_VALUE_MAX_ARGS 1
50 static const char *setValueDelim[SET_VALUE_MAX_ARGS] = {"=", ""};
51 static const char *queryValueDelim[QUERY_VALUE_MAX_ARGS] = {""};
53 /* Array used to extract the data type from a string in getDataType. */
54 typedef struct tagDataTypeMap
56 char mask[15];
57 DWORD dataType;
58 } dataTypeMap;
60 static const dataTypeMap typeMap[] =
62 {"hex:", REG_BINARY},/* could be REG_NONE (?) */
63 {"dword:", REG_DWORD},
64 {"hex(0):", REG_NONE},
65 {"hex(1):", REG_SZ},
66 {"hex(2):", REG_EXPAND_SZ},
67 {"hex(3):", REG_BINARY},
68 {"hex(4):", REG_DWORD},
69 {"hex(5):", REG_DWORD_BIG_ENDIAN},
70 {"hex(6):", REG_LINK},
71 {"hex(7):", REG_MULTI_SZ},
72 {"hex(8):", REG_RESOURCE_LIST},
73 {"hex(9):", REG_FULL_RESOURCE_DESCRIPTOR},
74 {"hex(10):", REG_RESOURCE_REQUIREMENTS_LIST},
75 {"hex(80000000):", 0x80000000},
76 {"hex(80000001):", 0x80000001},
77 {"hex(80000002):", 0x80000002},
78 {"hex(80000003):", 0x80000003},
79 {"hex(80000004):", 0x80000004},
80 {"hex(80000005):", 0x80000005},
81 {"hex(80000006):", 0x80000006},
82 {"hex(80000007):", 0x80000007},
83 {"hex(80000008):", 0x80000008},
84 {"hex(80000009):", 0x80000000},
85 {"hex(8000000a):", 0x8000000A}
87 const static int LAST_TYPE_MAP = sizeof(typeMap)/sizeof(dataTypeMap);
90 /*
91 * Forward declaration
93 typedef void (*commandAPI)(LPSTR lpsLine);
95 static void doSetValue(LPSTR lpsLine);
96 static void doDeleteValue(LPSTR lpsLine);
97 static void doCreateKey(LPSTR lpsLine);
98 static void doDeleteKey(LPSTR lpsLine);
99 static void doQueryValue(LPSTR lpsLine);
102 * current suuported api
104 static const char* commandNames[COMMAND_COUNT] = {
105 "setValue",
106 "deleteValue",
107 "createKey",
108 "deleteKey",
109 "queryValue"
113 * Pointers to processing entry points
115 static const commandAPI commandAPIs[COMMAND_COUNT] = {
116 doSetValue,
117 doDeleteValue,
118 doCreateKey,
119 doDeleteKey,
120 doQueryValue
124 * This array controls the registry saving needs at the end of the process
126 static const BOOL commandSaveRegistry[COMMAND_COUNT] = {
127 TRUE,
128 TRUE,
129 TRUE,
130 TRUE,
131 FALSE
135 * Generic prototyes
137 static HKEY getDataType(LPSTR *lpValue);
138 static LPSTR getRegKeyName(LPSTR lpLine);
139 static HKEY getRegClass(LPSTR lpLine);
140 static LPSTR getArg(LPSTR arg);
141 static INT getCommand(LPSTR commandName);
142 static DWORD convertHexToDWord(char *str, BYTE *buf);
143 static DWORD convertHexCSVToHex(char *str, BYTE *buf, ULONG bufLen);
144 static LPSTR convertHexToHexCSV( BYTE *buf, ULONG len);
145 static LPSTR convertHexToDWORDStr( BYTE *buf, ULONG len);
146 static HRESULT openKey(LPSTR stdInput);
147 static void closeKey();
150 * api setValue prototypes
152 static void processSetValue(LPSTR cmdline);
153 static HRESULT setValue(LPSTR *argv);
156 * api queryValue prototypes
158 static void processQueryValue(LPSTR cmdline);
161 * Help Text displyed when invalid parameters are provided
163 static char helpText[] = "
164 NAME
165 regapi - provide a command line interface to the wine registry.
167 SYNOPSYS
168 regapi commandName [-force] < file
170 DESCRIPTION
171 regapi allows editing the wine resgistry. It processes the given
172 commandName for every line in the stdin data stream. Input data
173 format may vary depending on the commandName see INPUT FILE FORMAT.
175 OPTIONS
176 commandName
177 Instruct regapi about what action to perform on the data stream.
178 Currently, only setValue and queryValue are supported and
179 implemented.
181 -force
182 When provided the action will be performed anyway. This may
183 have a different meaning depending on the context. For example,
184 when providing -force to setValue, the value is set even if it
185 was previously set to another value.
187 < file
188 STDIN chanel, provide a file name with line of the appropriate
189 format.
191 INPUT FILE FORMAT
193 setValue
194 The input file format required by the setValue command is similar
195 to the one obtained from regedit.exe export option. The only
196 difference is that multi line values are not supported, the
197 value data must be on a single line.
199 [KEY_CLASS\\Some\\Path\\For\\A\\Key]
200 \"Value1\"=\"Data1\"
201 \"Value2\"=\"Data2\"
202 \"Valuen\"=\"Datan\"
205 queryValue
206 The input file format required by the queryValue command is
207 similar to the one required by setValue. The only
208 difference is that you only provide the value name.
210 [KEY_CLASS\\Some\\Path\\For\\A\\Key]
211 \"Value1\"
212 \"Value2\"
213 \"Valuen\"
215 February 1999.
219 /******************************************************************************
220 * This funtion returns the HKEY associated with the data type encoded in the
221 * value. It modify the input parameter (key value) in order to skip this
222 * "now useless" data type information.
224 HKEY getDataType(LPSTR *lpValue)
226 INT counter = 0;
227 DWORD dwReturn = REG_SZ;
229 for (; counter < LAST_TYPE_MAP; counter++)
231 LONG len = strlen(typeMap[counter].mask);
232 if ( strncmpi( *lpValue, typeMap[counter].mask, len) == IDENTICAL)
235 * We found it, modify the value's pointer in order to skip the data
236 * type identifier, set the return value and exit the loop.
238 (*lpValue) += len;
239 dwReturn = typeMap[counter].dataType;
240 break;
244 return dwReturn;
246 /******************************************************************************
247 * Extracts from a [HKEY\some\key\path] type of line the key name (what starts
248 * after the first '\' and end before the ']'
250 LPSTR getRegKeyName(LPSTR lpLine)
252 LPSTR keyNameBeg = NULL;
253 LPSTR keyNameEnd = NULL;
254 char lpLineCopy[KEY_MAX_LEN];
256 if (lpLine == NULL)
257 return NULL;
259 strcpy(lpLineCopy, lpLine);
261 keyNameBeg = strstr(lpLineCopy, "\\"); /* The key name start by '\' */
262 keyNameBeg++; /* but is not part of the key name */
263 keyNameEnd = strstr(lpLineCopy, "]"); /* The key name end by ']' */
264 *keyNameEnd = NULL; /* Isolate the key name */
266 currentKeyName = HeapAlloc(GetProcessHeap(), 0, strlen(keyNameBeg)+1);
267 if (currentKeyName != NULL)
268 strcpy(currentKeyName, keyNameBeg);
270 return currentKeyName;
273 /******************************************************************************
274 * Extracts from a [HKEY/some/key/path] type of line the key class (what
275 * starts after the '[' and end before the first '\'
277 static HKEY getRegClass(LPSTR lpClass)
279 LPSTR classNameEnd;
280 LPSTR classNameBeg;
282 char lpClassCopy[KEY_MAX_LEN];
284 if (lpClass == NULL)
285 return ERROR_INVALID_PARAMETER;
287 strcpy(lpClassCopy, lpClass);
289 classNameEnd = strstr(lpClassCopy, "\\"); /* The class name end by '\' */
290 *classNameEnd = NULL; /* Isolate the class name */
291 classNameBeg = &lpClassCopy[1]; /* Skip the '[' */
293 if (strcmp( classNameBeg, "HKEY_LOCAL_MACHINE") == IDENTICAL )
294 return HKEY_LOCAL_MACHINE;
295 else if (strcmp( classNameBeg, "HKEY_USERS") == IDENTICAL )
296 return HKEY_USERS;
297 else if (strcmp( classNameBeg, "HKEY_CLASSES_ROOT") == IDENTICAL )
298 return HKEY_CLASSES_ROOT;
299 else if (strcmp( classNameBeg, "HKEY_CURRENT_CONFIG") == IDENTICAL )
300 return HKEY_CURRENT_CONFIG;
301 else if (strcmp( classNameBeg, "HKEY_CURRENT_USER") == IDENTICAL )
302 return HKEY_CURRENT_USER;
303 else
304 return ERROR_INVALID_PARAMETER;
307 /******************************************************************************
308 * Returns an allocated buffer with a cleaned copy (removed the surrounding
309 * dbl quotes) of the passed value.
311 static LPSTR getArg( LPSTR arg)
313 LPSTR tmp = NULL;
314 ULONG len;
316 if (arg == NULL)
317 return NULL;
320 * Get rid of surrounding quotes
322 len = strlen(arg);
324 if( arg[len-1] == '\"' ) arg[len-1] = NULL;
325 if( arg[0] == '\"' ) arg++;
327 tmp = HeapAlloc(GetProcessHeap(), 0, strlen(arg)+1);
328 strcpy(tmp, arg);
330 return tmp;
333 /******************************************************************************
334 * Returns the index in the commands array of the command to process.
336 static INT getCommand(LPSTR commandName)
338 INT count;
339 for (count=0; count < COMMAND_COUNT; count++)
340 if ( strcmp(commandName, commandNames[count]) == IDENTICAL)
341 return count;
343 return COMMAND_NOT_FOUND;
346 /******************************************************************************
347 * Converts a hex representation of a DWORD into a DWORD.
349 static DWORD convertHexToDWord(char *str, BYTE *buf)
351 char *s = str; /* Pointer to current */
352 char *b = buf; /* Pointer to result */
353 ULONG strPos = 0;
355 memset(buf, 0, 4);
357 while (strPos < 4) /* 8 byte in a DWORD */
359 char xbuf[3];
360 char wc;
362 memcpy(xbuf,s,2); xbuf[2]='\0';
363 sscanf(xbuf,"%02x",(UINT*)&wc);
364 *b++ =(unsigned char)wc;
366 s+=2;
367 strPos+=1;
370 return 4; /* always 4 byte for the word */
373 /******************************************************************************
374 * Converts a hex buffer into a hex coma separated values
376 static char* convertHexToHexCSV(BYTE *buf, ULONG bufLen)
378 char* str;
379 char* ptrStr;
380 BYTE* ptrBuf;
382 ULONG current = 0;
384 str = HeapAlloc(GetProcessHeap(), 0, (bufLen+1)*2);
385 memset(str, 0, (bufLen+1)*2);
386 ptrStr = str; /* Pointer to result */
387 ptrBuf = buf; /* Pointer to current */
389 while (current < bufLen)
391 BYTE bCur = ptrBuf[current++];
392 char res[3];
394 sprintf(res, "%02x", (unsigned int)*&bCur);
395 strcat(str, res);
396 strcat(str, ",");
399 /* Get rid of the last coma */
400 str[strlen(str)-1] = NULL;
401 return str;
404 /******************************************************************************
405 * Converts a hex buffer into a DWORD string
407 static char* convertHexToDWORDStr(BYTE *buf, ULONG bufLen)
409 char* str;
410 char* ptrStr;
411 BYTE* ptrBuf;
413 ULONG current = 0;
415 str = HeapAlloc(GetProcessHeap(), 0, (bufLen*2)+1);
416 memset(str, 0, (bufLen*2)+1);
417 ptrStr = str; /* Pointer to result */
418 ptrBuf = buf; /* Pointer to current */
420 while (current < bufLen)
422 BYTE bCur = ptrBuf[current++];
423 char res[3];
425 sprintf(res, "%02x", (unsigned int)*&bCur);
426 strcat(str, res);
429 /* Get rid of the last coma */
430 return str;
432 /******************************************************************************
433 * Converts a hex coma separated values list into a hex list.
435 static DWORD convertHexCSVToHex(char *str, BYTE *buf, ULONG bufLen)
437 char *s = str; /* Pointer to current */
438 char *b = buf; /* Pointer to result */
440 ULONG strLen = strlen(str);
441 ULONG strPos = 0;
442 DWORD byteCount = 0;
444 memset(buf, 0, bufLen);
447 * warn the user if we are here with a string longer than 2 bytes that does
448 * not contains ",". It is more likely because the data is invalid.
450 if ( ( strlen(str) > 2) && ( strstr(str, ",") == NULL) )
451 printf("regapi: WARNING converting CSV hex stream with no coma, "
452 "input data seems invalid.\n");
454 while (strPos < strLen)
456 char xbuf[3];
457 char wc;
459 memcpy(xbuf,s,2); xbuf[3]='\0';
460 sscanf(xbuf,"%02x",(UINT*)&wc);
461 *b++ =(unsigned char)wc;
463 s+=3;
464 strPos+=3;
465 byteCount++;
468 return byteCount;
472 /******************************************************************************
473 * Sets the value in argv[0] to the data in argv[1] for the currently
474 * opened key.
476 static HRESULT setValue(LPSTR *argv)
478 HRESULT hRes;
479 DWORD dwSize = KEY_MAX_LEN;
480 DWORD dwType = NULL;
481 DWORD dwDataType;
483 LPSTR lpsCurrentValue;
485 LPSTR keyValue = argv[0];
486 LPSTR keyData = argv[1];
488 /* Make some checks */
489 if ( (keyValue == NULL) || (keyData == NULL) )
490 return ERROR_INVALID_PARAMETER;
492 lpsCurrentValue=HeapAlloc(GetProcessHeap(), 0,KEY_MAX_LEN);
494 * Default registry values are encoded in the input stream as '@' but as
495 * blank in the wine registry.
497 if( (keyValue[0] == '@') && (strlen(keyValue) == 1) )
498 keyValue[0] = NULL;
500 /* Get the data type stored into the value field */
501 dwDataType = getDataType(&keyData);
503 memset(lpsCurrentValue, 0, KEY_MAX_LEN);
504 hRes = RegQueryValueExA(
505 currentKeyHandle,
506 keyValue,
507 NULL,
508 &dwType,
509 (LPBYTE)lpsCurrentValue,
510 &dwSize);
512 while(hRes==ERROR_MORE_DATA){
513 dwSize+=KEY_MAX_LEN;
514 lpsCurrentValue=HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,lpsCurrentValue,dwSize);
515 hRes = RegQueryValueExA(currentKeyHandle,keyValue,NULL,&dwType,(LPBYTE)lpsCurrentValue,&dwSize);
518 if( ( strlen(lpsCurrentValue) == 0 ) || /* The value is not existing */
519 ( bForce )) /* -force option */
521 LPBYTE lpbData;
522 BYTE convert[KEY_MAX_LEN];
523 DWORD dwLen;
525 if ( dwDataType == REG_SZ ) /* no convertion for string */
527 dwLen = strlen(keyData);
528 lpbData = keyData;
530 else if (dwDataType == REG_DWORD) /* Convert the dword types */
532 dwLen = convertHexToDWord(keyData, convert);
533 lpbData = convert;
535 else /* Convert the hexadecimal types */
537 dwLen = convertHexCSVToHex(keyData, convert, KEY_MAX_LEN);
538 lpbData = convert;
541 hRes = RegSetValueEx(
542 currentKeyHandle,
543 keyValue,
544 0, /* Reserved */
545 dwDataType,
546 lpbData,
547 dwLen);
549 else
551 /* return the current value data into argv[1] */
552 if (argv[1] != NULL)
554 HeapFree(GetProcessHeap(), 0, argv[1]);
555 argv[1] = HeapAlloc(GetProcessHeap(), 0, dwSize+1);
557 if ( argv[1] != NULL )
558 strncpy(argv[1], lpsCurrentValue, dwSize);
561 return KEY_VALUE_ALREADY_SET;
563 return hRes;
567 /******************************************************************************
568 * Open the key
570 static HRESULT openKey( LPSTR stdInput)
572 DWORD dwDisp;
573 HRESULT hRes;
575 /* Sanity checks */
576 if (stdInput == NULL)
577 return ERROR_INVALID_PARAMETER;
579 /* Get the registry class */
580 currentKeyClass = getRegClass(stdInput); /* Sets global variable */
581 if (currentKeyClass == ERROR_INVALID_PARAMETER)
582 return ERROR_INVALID_PARAMETER;
584 /* Get the key name */
585 currentKeyName = getRegKeyName(stdInput); /* Sets global variable */
586 if (currentKeyName == NULL)
587 return ERROR_INVALID_PARAMETER;
589 hRes = RegCreateKeyEx(
590 currentKeyClass, /* Class */
591 currentKeyName, /* Sub Key */
592 0, /* MUST BE 0 */
593 NULL, /* object type */
594 REG_OPTION_NON_VOLATILE, /* option, REG_OPTION_NON_VOLATILE ... */
595 KEY_ALL_ACCESS, /* access mask, KEY_ALL_ACCESS */
596 NULL, /* security attribute */
597 &currentKeyHandle, /* result */
598 &dwDisp); /* disposition, REG_CREATED_NEW_KEY or
599 REG_OPENED_EXISTING_KEY */
601 if (hRes == ERROR_SUCCESS)
602 bTheKeyIsOpen = TRUE;
604 return hRes;
607 /******************************************************************************
608 * This function is a wrapper arround the setValue function. It prepares the
609 * land and clean the area once completed.
611 static void processSetValue(LPSTR cmdline)
613 LPSTR argv[SET_VALUE_MAX_ARGS]; /* args storage */
615 LPSTR token = NULL; /* current token analized */
616 ULONG argCounter = 0; /* counter of args */
617 INT counter;
618 HRESULT hRes = NULL;
621 * Init storage and parse the line
623 for (counter=0; counter<SET_VALUE_MAX_ARGS; counter++)
624 argv[counter]=NULL;
626 while( (token = strsep(&cmdline, setValueDelim[argCounter])) != NULL )
628 argv[argCounter++] = getArg(token);
630 if (argCounter == SET_VALUE_MAX_ARGS)
631 break; /* Stop processing args no matter what */
634 hRes = setValue(argv);
635 if ( hRes == ERROR_SUCCESS )
636 printf(
637 "regapi: Value \"%s\" has been set to \"%s\" in key [%s]\n",
638 argv[0],
639 argv[1],
640 currentKeyName);
642 else if ( hRes == KEY_VALUE_ALREADY_SET )
643 printf(
644 "regapi: Value \"%s\" already set to \"%s\" in key [%s]\n",
645 argv[0],
646 argv[1],
647 currentKeyName);
649 else
650 printf("regapi: ERROR Key %s not created. Value: %s, Data: %s\n",
651 currentKeyName,
652 argv[0],
653 argv[1]);
656 * Do some cleanup
658 for (counter=0; counter<argCounter; counter++)
659 if (argv[counter] != NULL)
660 HeapFree(GetProcessHeap(), 0, argv[counter]);
663 /******************************************************************************
664 * This function is a wrapper arround the queryValue function. It prepares the
665 * land and clean the area once completed.
667 static void processQueryValue(LPSTR cmdline)
669 LPSTR argv[QUERY_VALUE_MAX_ARGS];/* args storage */
670 LPSTR token = NULL; /* current token analized */
671 ULONG argCounter = 0; /* counter of args */
672 INT counter;
673 HRESULT hRes = NULL;
674 LPSTR keyValue = NULL;
675 LPSTR lpsRes = NULL;
678 * Init storage and parse the line
680 for (counter=0; counter<QUERY_VALUE_MAX_ARGS; counter++)
681 argv[counter]=NULL;
683 while( (token = strsep(&cmdline, queryValueDelim[argCounter])) != NULL )
685 argv[argCounter++] = getArg(token);
687 if (argCounter == QUERY_VALUE_MAX_ARGS)
688 break; /* Stop processing args no matter what */
691 /* The value we look for is the first token on the line */
692 if ( argv[0] == NULL )
693 return; /* SHOULD NOT OCCURS */
694 else
695 keyValue = argv[0];
697 if( (keyValue[0] == '@') && (strlen(keyValue) == 1) )
699 LONG lLen = KEY_MAX_LEN;
700 CHAR* lpsData=HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,KEY_MAX_LEN);
702 * We need to query the key default value
704 hRes = RegQueryValue(
705 currentKeyHandle,
706 currentKeyName,
707 (LPBYTE)lpsData,
708 &lLen);
710 while(hRes==ERROR_MORE_DATA){
711 lLen+=KEY_MAX_LEN;
712 lpsData=HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,lpsData,lLen);
713 hRes = RegQueryValue(currentKeyHandle,currentKeyName,(LPBYTE)lpsData,&lLen);
716 if (hRes == ERROR_SUCCESS)
718 lpsRes = HeapAlloc( GetProcessHeap(), 0, lLen);
719 strncpy(lpsRes, lpsData, lLen);
722 else
724 DWORD dwLen = KEY_MAX_LEN;
725 BYTE* lpbData=HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,KEY_MAX_LEN);
726 DWORD dwType;
728 * We need to query a specific value for the key
730 hRes = RegQueryValueEx(
731 currentKeyHandle,
732 keyValue,
734 &dwType,
735 (LPBYTE)lpbData,
736 &dwLen);
738 while(hRes==ERROR_MORE_DATA){
739 dwLen+=KEY_MAX_LEN;
740 lpbData=HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,lpbData,dwLen);
741 hRes = RegQueryValueEx(currentKeyHandle,keyValue,NULL,&dwType,(LPBYTE)lpbData,&dwLen);
744 if (hRes == ERROR_SUCCESS)
747 * Convert the returned data to a displayable format
749 switch ( dwType )
751 case REG_SZ:
752 case REG_EXPAND_SZ:
754 lpsRes = HeapAlloc( GetProcessHeap(), 0, dwLen);
755 strncpy(lpsRes, lpbData, dwLen);
756 break;
758 case REG_DWORD:
760 lpsRes = convertHexToDWORDStr(lpbData, dwLen);
761 break;
763 default:
765 lpsRes = convertHexToHexCSV(lpbData, dwLen);
766 break;
771 HeapFree(GetProcessHeap(), 0, lpbData);
775 if ( hRes == ERROR_SUCCESS )
776 printf(
777 "regapi: Value \"%s\" = \"%s\" in key [%s]\n",
778 keyValue,
779 lpsRes,
780 currentKeyName);
782 else
783 printf("regapi: ERROR Value \"%s\" not found. for key \"%s\"\n",
784 keyValue,
785 currentKeyName);
788 * Do some cleanup
790 for (counter=0; counter<argCounter; counter++)
791 if (argv[counter] != NULL)
792 HeapFree(GetProcessHeap(), 0, argv[counter]);
794 if (lpsRes != NULL)
795 HeapFree(GetProcessHeap(), 0, lpsRes);
799 /******************************************************************************
800 * Close the currently opened key.
802 static void closeKey()
804 RegCloseKey(currentKeyHandle);
806 HeapFree(GetProcessHeap(), 0, currentKeyName); /* Allocated by getKeyName */
808 bTheKeyIsOpen = FALSE;
810 currentKeyName = NULL;
811 currentKeyClass = NULL;
812 currentKeyHandle = NULL;
815 /******************************************************************************
816 * This funtion is the main entry point to the setValue type of action. It
817 * receives the currently read line and dispatch the work depending on the
818 * context.
820 static void doSetValue(LPSTR stdInput)
823 * We encoutered the end of the file, make sure we
824 * close the opened key and exit
826 if (stdInput == NULL)
828 if (bTheKeyIsOpen != FALSE)
829 closeKey();
831 return;
834 if ( stdInput[0] == '[') /* We are reading a new key */
836 if ( bTheKeyIsOpen != FALSE )
837 closeKey(); /* Close the previous key before */
839 if ( openKey(stdInput) != ERROR_SUCCESS )
840 printf ("regapi: doSetValue failed to open key %s\n", stdInput);
842 else if( ( bTheKeyIsOpen ) &&
843 (( stdInput[0] == '@') || /* reading a default @=data pair */
844 ( stdInput[0] == '\"'))) /* reading a new value=data pair */
846 processSetValue(stdInput);
848 else /* since we are assuming that the */
849 { /* file format is valid we must */
850 if ( bTheKeyIsOpen ) /* be reading a blank line which */
851 closeKey(); /* indicate end of this key processing */
855 /******************************************************************************
856 * This funtion is the main entry point to the queryValue type of action. It
857 * receives the currently read line and dispatch the work depending on the
858 * context.
860 static void doQueryValue(LPSTR stdInput) {
862 * We encoutered the end of the file, make sure we
863 * close the opened key and exit
865 if (stdInput == NULL)
867 if (bTheKeyIsOpen != FALSE)
868 closeKey();
870 return;
873 if ( stdInput[0] == '[') /* We are reading a new key */
875 if ( bTheKeyIsOpen != FALSE )
876 closeKey(); /* Close the previous key before */
878 if ( openKey(stdInput) != ERROR_SUCCESS )
879 printf ("regapi: doSetValue failed to open key %s\n", stdInput);
881 else if( ( bTheKeyIsOpen ) &&
882 (( stdInput[0] == '@') || /* reading a default @=data pair */
883 ( stdInput[0] == '\"'))) /* reading a new value=data pair */
885 processQueryValue(stdInput);
887 else /* since we are assuming that the */
888 { /* file format is valid we must */
889 if ( bTheKeyIsOpen ) /* be reading a blank line which */
890 closeKey(); /* indicate end of this key processing */
894 /******************************************************************************
895 * This funtion is the main entry point to the deletetValue type of action. It
896 * receives the currently read line and dispatch the work depending on the
897 * context.
899 static void doDeleteValue(LPSTR line) {
900 printf ("regapi: deleteValue not yet implemented\n");
902 /******************************************************************************
903 * This funtion is the main entry point to the deleteKey type of action. It
904 * receives the currently read line and dispatch the work depending on the
905 * context.
907 static void doDeleteKey(LPSTR line) {
908 printf ("regapi: deleteKey not yet implemented\n");
910 /******************************************************************************
911 * This funtion is the main entry point to the createKey type of action. It
912 * receives the currently read line and dispatch the work depending on the
913 * context.
915 static void doCreateKey(LPSTR line) {
916 printf ("regapi: createKey not yet implemented\n");
919 /******************************************************************************
920 * MAIN - The main simply validate the first parameter (command to perform)
921 * It then read the STDIN lines by lines forwarding their processing
922 * to the appropriate method.
924 int PASCAL WinMain (HANDLE inst, HANDLE prev, LPSTR cmdline, int show)
926 LPSTR token = NULL; /* current token analized */
927 LPSTR stdInput = NULL; /* line read from stdin */
928 INT cmdIndex = -1; /* index of the command in array */
929 LPSTR nextLine = NULL;
930 ULONG currentSize = STDIN_MAX_LEN;
932 stdInput = HeapAlloc(GetProcessHeap(), 0, STDIN_MAX_LEN);
933 nextLine = HeapAlloc(GetProcessHeap(), 0, STDIN_MAX_LEN);
935 if (stdInput == NULL || nextLine== NULL)
936 return NOT_ENOUGH_MEMORY;
939 * get the command, should be the first arg (modify cmdLine)
941 token = strsep(&cmdline, " ");
942 if (token != NULL)
944 cmdIndex = getCommand(token);
945 if (cmdIndex == COMMAND_NOT_FOUND)
947 printf("regapi: Command \"%s\" is not supported.\n", token);
948 printf(helpText);
949 return COMMAND_NOT_SUPPORTED;
952 else
954 printf(
955 "regapi: The first item on the command line must be the command name.\n");
956 printf(helpText);
957 return COMMAND_NOT_SUPPORTED;
961 * check to see weather we force the action
962 * (meaning differ depending on the command performed)
964 if ( cmdline != NULL ) /* will be NULL if '-force' is not provided */
965 if ( strstr(cmdline, "-force") != NULL )
966 bForce = TRUE;
968 printf("Processing stdin...\n");
970 while ( TRUE )
973 * read a line
975 ULONG curSize=STDIN_MAX_LEN;
976 char* s=NULL;
978 while((NULL!=(stdInput=fgets(stdInput,curSize,stdin))) && (NULL==(s=strchr(stdInput,'\n'))) ){
979 fseek(stdin,-curSize,SEEK_CUR+1);
980 stdInput=HeapReAlloc(GetProcessHeap(), 0,stdInput,curSize+=STDIN_MAX_LEN);
983 * Make some handy generic stuff here...
985 if ( stdInput != NULL )
987 stdInput[strlen(stdInput) -1] = NULL; /* get rid of new line */
989 if( stdInput[0] == '#' ) /* this is a comment, skip */
990 continue;
992 while( stdInput[strlen(stdInput) -1] == '\\' ){ /* a '\' char in the end of the current line means */
993 /* that this line is not complete and we have to get */
994 stdInput[strlen(stdInput) -1]= NULL; /* the rest in the next lines */
996 nextLine = fgets(nextLine, STDIN_MAX_LEN, stdin);
998 nextLine[strlen(nextLine)-1] = NULL;
1000 if ( (strlen(stdInput)+strlen(nextLine)) > currentSize){
1002 stdInput=HeapReAlloc(GetProcessHeap(),0,stdInput,strlen(stdInput)+STDIN_MAX_LEN);
1004 currentSize+=STDIN_MAX_LEN;
1007 strcat(stdInput,nextLine+2);
1012 * We process every lines even the NULL (last) line, to indicate the
1013 * end of the processing to the specific process.
1015 commandAPIs[cmdIndex](stdInput);
1017 if (stdInput == NULL) /* EOF encountered */
1018 break;
1022 * Save the registry only if it was modified
1024 if ( commandSaveRegistry[cmdIndex] != FALSE )
1025 SHELL_SaveRegistry();
1027 HeapFree(GetProcessHeap(), 0, nextLine);
1029 HeapFree(GetProcessHeap(), 0, stdInput);
1031 return SUCCESS;