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
= 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
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 suuported 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 displyed when invalid parameters are provided
163 static char helpText
[] = "
165 regapi - provide a command line interface to the wine registry.
168 regapi commandName [-force] < file
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.
177 Instruct regapi about what action to perform on the data stream.
178 Currently, only setValue and queryValue are supported and
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.
188 STDIN chanel, provide a file name with line of the appropriate
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]
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]
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
)
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.
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
= 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
)
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
= 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
)
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] = NULL
;
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 coma 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 coma */
400 str
[strlen(str
)-1] = NULL
;
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 coma */
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
);
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
)
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
);
561 return KEY_VALUE_ALREADY_SET
;
567 /******************************************************************************
570 static HRESULT
openKey( LPSTR stdInput
)
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 */
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 ¤tKeyHandle
, /* result */
598 &dwDisp
); /* disposition, REG_CREATED_NEW_KEY or
599 REG_OPENED_EXISTING_KEY */
601 if (hRes
== ERROR_SUCCESS
)
602 bTheKeyIsOpen
= TRUE
;
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 */
621 * Init storage and parse the line
623 for (counter
=0; counter
<SET_VALUE_MAX_ARGS
; counter
++)
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
)
637 "regapi: Value \"%s\" has been set to \"%s\" in key [%s]\n",
642 else if ( hRes
== KEY_VALUE_ALREADY_SET
)
644 "regapi: Value \"%s\" already set to \"%s\" in key [%s]\n",
650 printf("regapi: ERROR Key %s not created. Value: %s, Data: %s\n",
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 */
674 LPSTR keyValue
= NULL
;
678 * Init storage and parse the line
680 for (counter
=0; counter
<QUERY_VALUE_MAX_ARGS
; counter
++)
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 */
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(
710 while(hRes
==ERROR_MORE_DATA
){
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
);
724 DWORD dwLen
= KEY_MAX_LEN
;
725 BYTE
* lpbData
=HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,KEY_MAX_LEN
);
728 * We need to query a specific value for the key
730 hRes
= RegQueryValueEx(
738 while(hRes
==ERROR_MORE_DATA
){
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
754 lpsRes
= HeapAlloc( GetProcessHeap(), 0, dwLen
);
755 strncpy(lpsRes
, lpbData
, dwLen
);
760 lpsRes
= convertHexToDWORDStr(lpbData
, dwLen
);
765 lpsRes
= convertHexToHexCSV(lpbData
, dwLen
);
771 HeapFree(GetProcessHeap(), 0, lpbData
);
775 if ( hRes
== ERROR_SUCCESS
)
777 "regapi: Value \"%s\" = \"%s\" in key [%s]\n",
783 printf("regapi: ERROR Value \"%s\" not found. for key \"%s\"\n",
790 for (counter
=0; counter
<argCounter
; counter
++)
791 if (argv
[counter
] != NULL
)
792 HeapFree(GetProcessHeap(), 0, argv
[counter
]);
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
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
)
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
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
)
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
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
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
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
, " ");
944 cmdIndex
= getCommand(token
);
945 if (cmdIndex
== COMMAND_NOT_FOUND
)
947 printf("regapi: Command \"%s\" is not supported.\n", token
);
949 return COMMAND_NOT_SUPPORTED
;
955 "regapi: The first item on the command line must be the command name.\n");
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
)
968 printf("Processing stdin...\n");
975 ULONG curSize
=STDIN_MAX_LEN
;
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 */
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 */
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
);