2 * Command line Registry implementation
4 * Copyright 1999 Sylvain St-Germain
6 * Note: Please consult the README file for more information.
19 /******************************************************************************
23 #define COMMAND_COUNT 5
25 #define KEY_MAX_LEN 1024
26 #define STDIN_MAX_LEN 2048
29 #define COMMAND_NOT_FOUND -1
31 #define NOT_ENOUGH_MEMORY 1
32 #define KEY_VALUE_ALREADY_SET 2
33 #define COMMAND_NOT_SUPPORTED 3
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
= 0;
42 static HKEY currentKeyHandle
= 0;
43 static BOOL bTheKeyIsOpen
= FALSE
;
45 /* Delimiters used to parse the "value"="data" pair for setValue*/
46 #define SET_VALUE_MAX_ARGS 2
47 /* Delimiters 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
60 static const dataTypeMap typeMap
[] =
62 {"hex:", REG_BINARY
},/* could be REG_NONE (?) */
63 {"dword:", REG_DWORD
},
64 {"hex(0):", REG_NONE
},
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
);
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 supported api
104 static const char* commandNames
[COMMAND_COUNT
] = {
113 * Pointers to processing entry points
115 static const commandAPI commandAPIs
[COMMAND_COUNT
] = {
124 * This array controls the registry saving needs at the end of the process
126 static const BOOL commandSaveRegistry
[COMMAND_COUNT
] = {
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 displayed when invalid parameters are provided
163 static char helpText
[] =
165 " regapi - provide a command line interface to the wine registry.\n"
168 " regapi commandName [-force] < file\n"
171 " regapi allows editing the wine registry. It processes the given\n"
172 " commandName for every line in the stdin data stream. Input data\n"
173 " format may vary depending on the commandName see INPUT FILE FORMAT.\n"
177 " Instruct regapi about what action to perform on the data stream.\n"
178 " Currently, only setValue and queryValue are supported and\n"
182 " When provided the action will be performed anyway. This may\n"
183 " have a different meaning depending on the context. For example,\n"
184 " when providing -force to setValue, the value is set even if it\n"
185 " was previously set to another value.\n"
188 " STDIN channel, provide a file name with line of the appropriate\n"
191 "INPUT FILE FORMAT\n"
194 " The input file format required by the setValue command is similar\n"
195 " to the one obtained from regedit.exe export option. The only\n"
196 " difference is that multi line values are not supported, the\n"
197 " value data must be on a single line.\n"
199 " [KEY_CLASS\\Some\\Path\\For\\A\\Key]\n"
200 " \"Value1\"=\"Data1\"\n"
201 " \"Value2\"=\"Data2\"\n"
202 " \"Valuen\"=\"Datan\"\n"
206 " The input file format required by the queryValue command is\n"
207 " similar to the one required by setValue. The only\n"
208 " difference is that you only provide the value name.\n"
210 " [KEY_CLASS\\Some\\Path\\For\\A\\Key]\n"
219 /******************************************************************************
220 * This function 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
)
227 DWORD dwReturn
= REG_SZ
;
229 for (; counter
< LAST_TYPE_MAP
; counter
++)
231 LONG len
= strlen(typeMap
[counter
].mask
);
232 if ( strncasecmp( *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.
239 dwReturn
= typeMap
[counter
].dataType
;
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
];
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
= '\0'; /* 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
)
282 char lpClassCopy
[KEY_MAX_LEN
];
285 return ERROR_INVALID_PARAMETER
;
287 strcpy(lpClassCopy
, lpClass
);
289 classNameEnd
= strstr(lpClassCopy
, "\\"); /* The class name end by '\' */
290 *classNameEnd
= '\0'; /* 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
)
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
;
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
)
320 * Get rid of surrounding quotes
324 if( arg
[len
-1] == '\"' ) arg
[len
-1] = '\0';
325 if( arg
[0] == '\"' ) arg
++;
327 tmp
= HeapAlloc(GetProcessHeap(), 0, strlen(arg
)+1);
333 /******************************************************************************
334 * Returns the index in the commands array of the command to process.
336 static INT
getCommand(LPSTR commandName
)
339 for (count
=0; count
< COMMAND_COUNT
; count
++)
340 if ( strcmp(commandName
, commandNames
[count
]) == IDENTICAL
)
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 */
357 while (strPos
< 4) /* 8 byte in a DWORD */
362 memcpy(xbuf
,s
,2); xbuf
[2]='\0';
363 sscanf(xbuf
,"%02x",(UINT
*)&wc
);
364 *b
++ =(unsigned char)wc
;
370 return 4; /* always 4 byte for the word */
373 /******************************************************************************
374 * Converts a hex buffer into a hex comma separated values
376 static char* convertHexToHexCSV(BYTE
*buf
, ULONG bufLen
)
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
++];
394 sprintf(res
, "%02x", (unsigned int)*&bCur
);
399 /* Get rid of the last comma */
400 str
[strlen(str
)-1] = '\0';
404 /******************************************************************************
405 * Converts a hex buffer into a DWORD string
407 static char* convertHexToDWORDStr(BYTE
*buf
, ULONG bufLen
)
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
++];
425 sprintf(res
, "%02x", (unsigned int)*&bCur
);
429 /* Get rid of the last comma */
432 /******************************************************************************
433 * Converts a hex comma 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
);
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 comma, "
452 "input data seems invalid.\n");
454 while (strPos
< strLen
)
459 memcpy(xbuf
,s
,2); xbuf
[3]='\0';
460 sscanf(xbuf
,"%02x",(UINT
*)&wc
);
461 *b
++ =(unsigned char)wc
;
472 /******************************************************************************
473 * Sets the value in argv[0] to the data in argv[1] for the currently
476 static HRESULT
setValue(LPSTR
*argv
)
479 DWORD dwSize
= KEY_MAX_LEN
;
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) )
500 /* Get the data type stored into the value field */
501 dwDataType
= getDataType(&keyData
);
503 memset(lpsCurrentValue
, 0, KEY_MAX_LEN
);
504 hRes
= RegQueryValueExA(
509 (LPBYTE
)lpsCurrentValue
,
512 while(hRes
==ERROR_MORE_DATA
){
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 */
522 BYTE convert
[KEY_MAX_LEN
];
525 if ( dwDataType
== REG_SZ
) /* no convertion for string */
527 dwLen
= strlen(keyData
);
530 else if (dwDataType
== REG_DWORD
) /* Convert the dword types */
532 dwLen
= convertHexToDWord(keyData
, convert
);
535 else /* Convert the hexadecimal types */
537 dwLen
= convertHexCSVToHex(keyData
, convert
, KEY_MAX_LEN
);
541 hRes
= RegSetValueEx(
551 /* return the current value data into argv[1] */
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
);
559 argv
[1][dwSize
]='\0';
563 return KEY_VALUE_ALREADY_SET
;
569 /******************************************************************************
572 static HRESULT
openKey( LPSTR stdInput
)
578 if (stdInput
== NULL
)
579 return ERROR_INVALID_PARAMETER
;
581 /* Get the registry class */
582 currentKeyClass
= getRegClass(stdInput
); /* Sets global variable */
583 if (currentKeyClass
== ERROR_INVALID_PARAMETER
)
584 return ERROR_INVALID_PARAMETER
;
586 /* Get the key name */
587 currentKeyName
= getRegKeyName(stdInput
); /* Sets global variable */
588 if (currentKeyName
== NULL
)
589 return ERROR_INVALID_PARAMETER
;
591 hRes
= RegCreateKeyEx(
592 currentKeyClass
, /* Class */
593 currentKeyName
, /* Sub Key */
595 NULL
, /* object type */
596 REG_OPTION_NON_VOLATILE
, /* option, REG_OPTION_NON_VOLATILE ... */
597 KEY_ALL_ACCESS
, /* access mask, KEY_ALL_ACCESS */
598 NULL
, /* security attribute */
599 ¤tKeyHandle
, /* result */
600 &dwDisp
); /* disposition, REG_CREATED_NEW_KEY or
601 REG_OPENED_EXISTING_KEY */
603 if (hRes
== ERROR_SUCCESS
)
604 bTheKeyIsOpen
= TRUE
;
609 /******************************************************************************
610 * This function is a wrapper arround the setValue function. It prepares the
611 * land and clean the area once completed.
613 static void processSetValue(LPSTR cmdline
)
615 LPSTR argv
[SET_VALUE_MAX_ARGS
]; /* args storage */
617 LPSTR token
= NULL
; /* current token analized */
618 ULONG argCounter
= 0; /* counter of args */
623 * Init storage and parse the line
625 for (counter
=0; counter
<SET_VALUE_MAX_ARGS
; counter
++)
628 while( (token
= strsep(&cmdline
, setValueDelim
[argCounter
])) != NULL
)
630 argv
[argCounter
++] = getArg(token
);
632 if (argCounter
== SET_VALUE_MAX_ARGS
)
633 break; /* Stop processing args no matter what */
636 hRes
= setValue(argv
);
637 if ( hRes
== ERROR_SUCCESS
)
639 "regapi: Value \"%s\" has been set to \"%s\" in key [%s]\n",
644 else if ( hRes
== KEY_VALUE_ALREADY_SET
)
646 "regapi: Value \"%s\" already set to \"%s\" in key [%s]\n",
652 printf("regapi: ERROR Key %s not created. Value: %s, Data: %s\n",
660 for (counter
=0; counter
<argCounter
; counter
++)
661 if (argv
[counter
] != NULL
)
662 HeapFree(GetProcessHeap(), 0, argv
[counter
]);
665 /******************************************************************************
666 * This function is a wrapper arround the queryValue function. It prepares the
667 * land and clean the area once completed.
669 static void processQueryValue(LPSTR cmdline
)
671 LPSTR argv
[QUERY_VALUE_MAX_ARGS
];/* args storage */
672 LPSTR token
= NULL
; /* current token analized */
673 ULONG argCounter
= 0; /* counter of args */
676 LPSTR keyValue
= NULL
;
680 * Init storage and parse the line
682 for (counter
=0; counter
<QUERY_VALUE_MAX_ARGS
; counter
++)
685 while( (token
= strsep(&cmdline
, queryValueDelim
[argCounter
])) != NULL
)
687 argv
[argCounter
++] = getArg(token
);
689 if (argCounter
== QUERY_VALUE_MAX_ARGS
)
690 break; /* Stop processing args no matter what */
693 /* The value we look for is the first token on the line */
694 if ( argv
[0] == NULL
)
695 return; /* SHOULD NOT OCCURS */
699 if( (keyValue
[0] == '@') && (strlen(keyValue
) == 1) )
701 LONG lLen
= KEY_MAX_LEN
;
702 CHAR
* lpsData
=HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,KEY_MAX_LEN
);
704 * We need to query the key default value
706 hRes
= RegQueryValue(
712 if (hRes
==ERROR_MORE_DATA
) {
713 lpsData
=HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,lpsData
,lLen
);
714 hRes
= RegQueryValue(currentKeyHandle
,currentKeyName
,(LPBYTE
)lpsData
,&lLen
);
717 if (hRes
== ERROR_SUCCESS
)
719 lpsRes
= HeapAlloc( GetProcessHeap(), 0, lLen
);
720 strncpy(lpsRes
, lpsData
, lLen
);
726 DWORD dwLen
= KEY_MAX_LEN
;
727 BYTE
* lpbData
=HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,KEY_MAX_LEN
);
730 * We need to query a specific value for the key
732 hRes
= RegQueryValueEx(
740 if (hRes
==ERROR_MORE_DATA
) {
741 lpbData
=HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,lpbData
,dwLen
);
742 hRes
= RegQueryValueEx(currentKeyHandle
,keyValue
,NULL
,&dwType
,(LPBYTE
)lpbData
,&dwLen
);
745 if (hRes
== ERROR_SUCCESS
)
748 * Convert the returned data to a displayable format
755 lpsRes
= HeapAlloc( GetProcessHeap(), 0, dwLen
);
756 strncpy(lpsRes
, lpbData
, dwLen
);
757 lpsRes
[dwLen
-1]='\0';
762 lpsRes
= convertHexToDWORDStr(lpbData
, dwLen
);
767 lpsRes
= convertHexToHexCSV(lpbData
, dwLen
);
773 HeapFree(GetProcessHeap(), 0, lpbData
);
777 if ( hRes
== ERROR_SUCCESS
)
779 "regapi: Value \"%s\" = \"%s\" in key [%s]\n",
785 printf("regapi: ERROR Value \"%s\" not found. for key \"%s\"\n",
792 for (counter
=0; counter
<argCounter
; counter
++)
793 if (argv
[counter
] != NULL
)
794 HeapFree(GetProcessHeap(), 0, argv
[counter
]);
797 HeapFree(GetProcessHeap(), 0, lpsRes
);
801 /******************************************************************************
802 * Close the currently opened key.
804 static void closeKey()
806 RegCloseKey(currentKeyHandle
);
808 HeapFree(GetProcessHeap(), 0, currentKeyName
); /* Allocated by getKeyName */
810 bTheKeyIsOpen
= FALSE
;
812 currentKeyName
= NULL
;
814 currentKeyHandle
= 0;
817 /******************************************************************************
818 * This funtion is the main entry point to the setValue type of action. It
819 * receives the currently read line and dispatch the work depending on the
822 static void doSetValue(LPSTR stdInput
)
825 * We encoutered the end of the file, make sure we
826 * close the opened key and exit
828 if (stdInput
== NULL
)
830 if (bTheKeyIsOpen
!= FALSE
)
836 if ( stdInput
[0] == '[') /* We are reading a new key */
838 if ( bTheKeyIsOpen
!= FALSE
)
839 closeKey(); /* Close the previous key before */
841 if ( openKey(stdInput
) != ERROR_SUCCESS
)
842 printf ("regapi: doSetValue failed to open key %s\n", stdInput
);
844 else if( ( bTheKeyIsOpen
) &&
845 (( stdInput
[0] == '@') || /* reading a default @=data pair */
846 ( stdInput
[0] == '\"'))) /* reading a new value=data pair */
848 processSetValue(stdInput
);
850 else /* since we are assuming that the */
851 { /* file format is valid we must */
852 if ( bTheKeyIsOpen
) /* be reading a blank line which */
853 closeKey(); /* indicate end of this key processing */
857 /******************************************************************************
858 * This funtion is the main entry point to the queryValue type of action. It
859 * receives the currently read line and dispatch the work depending on the
862 static void doQueryValue(LPSTR stdInput
) {
864 * We encoutered the end of the file, make sure we
865 * close the opened key and exit
867 if (stdInput
== NULL
)
869 if (bTheKeyIsOpen
!= FALSE
)
875 if ( stdInput
[0] == '[') /* We are reading a new key */
877 if ( bTheKeyIsOpen
!= FALSE
)
878 closeKey(); /* Close the previous key before */
880 if ( openKey(stdInput
) != ERROR_SUCCESS
)
881 printf ("regapi: doSetValue failed to open key %s\n", stdInput
);
883 else if( ( bTheKeyIsOpen
) &&
884 (( stdInput
[0] == '@') || /* reading a default @=data pair */
885 ( stdInput
[0] == '\"'))) /* reading a new value=data pair */
887 processQueryValue(stdInput
);
889 else /* since we are assuming that the */
890 { /* file format is valid we must */
891 if ( bTheKeyIsOpen
) /* be reading a blank line which */
892 closeKey(); /* indicate end of this key processing */
896 /******************************************************************************
897 * This funtion is the main entry point to the deletetValue type of action. It
898 * receives the currently read line and dispatch the work depending on the
901 static void doDeleteValue(LPSTR line
) {
902 printf ("regapi: deleteValue not yet implemented\n");
904 /******************************************************************************
905 * This funtion is the main entry point to the deleteKey type of action. It
906 * receives the currently read line and dispatch the work depending on the
909 static void doDeleteKey(LPSTR line
) {
910 printf ("regapi: deleteKey not yet implemented\n");
912 /******************************************************************************
913 * This funtion is the main entry point to the createKey type of action. It
914 * receives the currently read line and dispatch the work depending on the
917 static void doCreateKey(LPSTR line
) {
918 printf ("regapi: createKey not yet implemented\n");
921 /******************************************************************************
922 * MAIN - The main simply validate the first parameter (command to perform)
923 * It then read the STDIN lines by lines forwarding their processing
924 * to the appropriate method.
926 int PASCAL
WinMain (HANDLE inst
, HANDLE prev
, LPSTR cmdline
, int show
)
928 LPSTR token
= NULL
; /* current token analized */
929 LPSTR stdInput
= NULL
; /* line read from stdin */
930 INT cmdIndex
= -1; /* index of the command in array */
931 LPSTR nextLine
= NULL
;
932 ULONG currentSize
= STDIN_MAX_LEN
;
934 stdInput
= HeapAlloc(GetProcessHeap(), 0, STDIN_MAX_LEN
);
935 nextLine
= HeapAlloc(GetProcessHeap(), 0, STDIN_MAX_LEN
);
937 if (stdInput
== NULL
|| nextLine
== NULL
)
938 return NOT_ENOUGH_MEMORY
;
941 * get the command, should be the first arg (modify cmdLine)
943 token
= strsep(&cmdline
, " ");
946 cmdIndex
= getCommand(token
);
947 if (cmdIndex
== COMMAND_NOT_FOUND
)
949 printf("regapi: Command \"%s\" is not supported.\n", token
);
951 return COMMAND_NOT_SUPPORTED
;
957 "regapi: The first item on the command line must be the command name.\n");
959 return COMMAND_NOT_SUPPORTED
;
963 * check to see weather we force the action
964 * (meaning differ depending on the command performed)
966 if ( cmdline
!= NULL
) /* will be NULL if '-force' is not provided */
967 if ( strstr(cmdline
, "-force") != NULL
)
970 printf("Processing stdin...\n");
977 ULONG curSize
=STDIN_MAX_LEN
;
980 while((NULL
!=(stdInput
=fgets(stdInput
,curSize
,stdin
))) && (NULL
==(s
=strchr(stdInput
,'\n'))) ){
981 fseek(stdin
,-curSize
,SEEK_CUR
+1);
982 stdInput
=HeapReAlloc(GetProcessHeap(), 0,stdInput
,curSize
+=STDIN_MAX_LEN
);
985 * Make some handy generic stuff here...
987 if ( stdInput
!= NULL
)
989 stdInput
[strlen(stdInput
) -1] = '\0'; /* get rid of new line */
991 if( stdInput
[0] == '#' ) /* this is a comment, skip */
994 while( stdInput
[strlen(stdInput
) -1] == '\\' ){ /* a '\' char in the end of the current line means */
995 /* that this line is not complete and we have to get */
996 stdInput
[strlen(stdInput
) -1]= '\0'; /* the rest in the next lines */
998 nextLine
= fgets(nextLine
, STDIN_MAX_LEN
, stdin
);
1000 nextLine
[strlen(nextLine
)-1] = '\0';
1002 if ( (strlen(stdInput
)+strlen(nextLine
)) > currentSize
){
1004 stdInput
=HeapReAlloc(GetProcessHeap(),0,stdInput
,strlen(stdInput
)+STDIN_MAX_LEN
);
1006 currentSize
+=STDIN_MAX_LEN
;
1009 strcat(stdInput
,nextLine
+2);
1014 * We process every lines even the NULL (last) line, to indicate the
1015 * end of the processing to the specific process.
1017 commandAPIs
[cmdIndex
](stdInput
);
1019 if (stdInput
== NULL
) /* EOF encountered */
1025 * Save the registry only if it was modified
1027 if ( commandSaveRegistry
[cmdIndex
] != FALSE
)
1028 SHELL_SaveRegistry();
1030 HeapFree(GetProcessHeap(), 0, nextLine
);
1032 HeapFree(GetProcessHeap(), 0, stdInput
);