Added an unknown VxD error code.
[wine] / programs / regapi / regapi.c
1 /*
2  * Command line Registry implementation
3  *
4  * Copyright 1999 Sylvain St-Germain
5  *
6  * Note: Please consult the README file for more information.
7  *
8  */
9
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <windows.h>
13 #include <winreg.h>
14 #include <winerror.h>
15 #include <winnt.h>
16 #include <string.h>
17
18 /******************************************************************************
19  * Defines and consts
20  */
21 #define IDENTICAL             0 
22 #define COMMAND_COUNT         7
23
24 #define KEY_MAX_LEN           1024 
25 #define STDIN_MAX_LEN         2048
26
27 /* Return values */
28 #define COMMAND_NOT_FOUND     -1
29 #define SUCCESS               0
30 #define NOT_ENOUGH_MEMORY     1
31 #define KEY_VALUE_ALREADY_SET 2
32 #define COMMAND_NOT_SUPPORTED 3
33
34 /* Generic global */
35 static BOOL bForce            = FALSE; /* Is set to TRUE when -force is
36                                           passed on the command line */
37
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;
43
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 
48
49 static const char *setValueDelim[SET_VALUE_MAX_ARGS]   = {"=", ""};  
50 static const char *queryValueDelim[QUERY_VALUE_MAX_ARGS]   = {""};  
51
52 /* Array used to extract the data type from a string in getDataType. */
53 typedef struct tagDataTypeMap
54 {
55   char  mask[15];
56   DWORD dataType;
57 } dataTypeMap; 
58   
59 static const dataTypeMap typeMap[] = 
60 {
61   {"hex:",            REG_BINARY},/* could be REG_NONE (?) */
62   {"dword:",          REG_DWORD},
63   {"hex(0):",         REG_NONE},
64   {"hex(1):",         REG_SZ},
65   {"hex(2):",         REG_EXPAND_SZ},
66   {"hex(3):",         REG_BINARY},
67   {"hex(4):",         REG_DWORD},
68   {"hex(5):",         REG_DWORD_BIG_ENDIAN},
69   {"hex(6):",         REG_LINK},
70   {"hex(7):",         REG_MULTI_SZ},
71   {"hex(8):",         REG_RESOURCE_LIST},
72   {"hex(9):",         REG_FULL_RESOURCE_DESCRIPTOR},
73   {"hex(10):",        REG_RESOURCE_REQUIREMENTS_LIST},
74   {"hex(80000000):",  0x80000000},
75   {"hex(80000001):",  0x80000001},
76   {"hex(80000002):",  0x80000002},
77   {"hex(80000003):",  0x80000003},
78   {"hex(80000004):",  0x80000004},
79   {"hex(80000005):",  0x80000005},
80   {"hex(80000006):",  0x80000006},
81   {"hex(80000007):",  0x80000007},
82   {"hex(80000008):",  0x80000008},
83   {"hex(80000009):",  0x80000000},
84   {"hex(8000000a):",  0x8000000A}
85 };
86 const static int LAST_TYPE_MAP = sizeof(typeMap)/sizeof(dataTypeMap);
87
88
89 /* 
90  * Forward declaration 
91  */
92 typedef void (*commandAPI)(LPSTR lpsLine);
93
94 static void doSetValue(LPSTR lpsLine);
95 static void doDeleteValue(LPSTR lpsLine);
96 static void doCreateKey(LPSTR lpsLine);
97 static void doDeleteKey(LPSTR lpsLine);
98 static void doQueryValue(LPSTR lpsLine);
99 static void doRegisterDLL(LPSTR lpsLine);
100 static void doUnregisterDLL(LPSTR lpsLine);
101
102 /*
103  * Currently supported api
104  */
105 static const char* commandNames[COMMAND_COUNT] = {
106   "setValue", 
107   "deleteValue", 
108   "createKey",
109   "deleteKey",
110   "queryValue",
111   "registerDLL",
112   "unregisterDLL"
113 };
114
115 /*
116  * Pointers to processing entry points
117  */
118 static const commandAPI commandAPIs[COMMAND_COUNT] = {
119   doSetValue, 
120   doDeleteValue, 
121   doCreateKey,
122   doDeleteKey,
123   doQueryValue,
124   doRegisterDLL,
125   doUnregisterDLL
126 };
127
128 /* 
129  * This array controls the registry saving needs at the end of the process 
130  */
131 static const BOOL commandSaveRegistry[COMMAND_COUNT] = {
132   TRUE,
133   TRUE,
134   TRUE,
135   TRUE,
136   FALSE,
137   TRUE,
138   TRUE
139 };
140
141 /* 
142  * Generic prototypes
143  */
144 static DWORD   getDataType(LPSTR *lpValue);
145 static LPSTR   getRegKeyName(LPSTR lpLine);
146 static HKEY    getRegClass(LPSTR lpLine);
147 static LPSTR   getArg(LPSTR arg);
148 static INT     getCommand(LPSTR commandName);
149 static DWORD   convertHexToDWord(char *str, BYTE *buf);
150 static DWORD   convertHexCSVToHex(char *str, BYTE *buf, ULONG bufLen);
151 static LPSTR   convertHexToHexCSV( BYTE *buf, ULONG len);
152 static LPSTR   convertHexToDWORDStr( BYTE *buf, ULONG len);
153 static HRESULT openKey(LPSTR stdInput);
154 static void    closeKey();
155
156 /* 
157  * api setValue prototypes
158  */
159 static void    processSetValue(LPSTR cmdline);
160 static HRESULT setValue(LPSTR *argv);
161
162 /* 
163  * api queryValue prototypes
164  */
165 static void    processQueryValue(LPSTR cmdline);
166
167 /*
168  * Help Text displayed when invalid parameters are provided
169  */
170 static char helpText[] =
171 "NAME\n"
172 "          regapi - provide a command line interface to the wine registry.\n"
173 "\n"
174 "SYNOPSIS\n"
175 "          regapi commandName [-force] < file\n"
176 "\n"
177 "DESCRIPTION\n"
178 "          regapi allows editing the wine registry.  It processes the given\n"
179 "          commandName for every line in the stdin data stream.  Input data\n"
180 "          format may vary depending on the commandName see INPUT FILE FORMAT.\n"
181 "\n"
182 "OPTIONS\n"
183 "          commandName\n"
184 "              Instruct regapi about what action to perform on the data stream.\n"
185 "              Currently, only setValue and queryValue are supported and\n"
186 "              implemented.\n"
187 "\n"
188 "          -force\n"
189 "              When provided the action will be performed anyway.  This may\n"
190 "              have a different meaning depending on the context.  For example,\n"
191 "              when providing -force to setValue, the value is set even if it\n"
192 "              was previously set to another value.\n"
193 "\n"
194 "          < file\n"
195 "              STDIN channel, provide a file name with line of the appropriate\n"
196 "              format.\n"
197 "\n"
198 "INPUT FILE FORMAT\n"
199 "\n"
200 "          setValue\n"
201 "              The input file format required by the setValue command is similar\n"
202 "              to the one obtained from regedit.exe export option.  The only\n"
203 "              difference is that multi line values are not supported, the\n"
204 "              value data must be on a single line.\n"
205 "\n"
206 "              [KEY_CLASS\\Some\\Path\\For\\A\\Key]\n"
207 "              \"Value1\"=\"Data1\"\n"
208 "              \"Value2\"=\"Data2\"\n"
209 "              \"Valuen\"=\"Datan\"\n"
210 "              ...\n"
211 "\n"
212 "          queryValue\n"
213 "              The input file format required by the queryValue command is\n"
214 "              similar to the one required by setValue.  The only\n"
215 "              difference is that you only provide the value name.\n"
216 "\n"
217 "              [KEY_CLASS\\Some\\Path\\For\\A\\Key]\n"
218 "              \"Value1\"\n"
219 "              \"Value2\"\n"
220 "              \"Valuen\"\n"
221 "              ...\n"
222 "           registerDLL\n"
223 "               The input file format is a list of DLLs to register\n"
224 "\n"
225 "           unregisterDLL\n"
226 "               The input file format is a list of DLLs to unregister\n"
227 "                                February 1999.\n"
228 ;
229               
230
231 /******************************************************************************
232  * This function returns the HKEY associated with the data type encoded in the 
233  * value.  It modifies the input parameter (key value) in order to skip this 
234  * "now useless" data type information.
235  */
236 DWORD getDataType(LPSTR *lpValue) 
237 {
238   INT   counter  = 0;
239   DWORD dwReturn = REG_SZ;
240
241   for (; counter < LAST_TYPE_MAP; counter++)
242   {
243     LONG len = strlen(typeMap[counter].mask);
244     if ( strncasecmp( *lpValue, typeMap[counter].mask, len) == IDENTICAL)
245     {
246       /*
247        * We found it, modify the value's pointer in order to skip the data 
248        * type identifier, set the return value and exit the loop.
249        */
250       (*lpValue) += len;
251       dwReturn    = typeMap[counter].dataType;
252       break; 
253     }
254   }
255
256   return dwReturn;
257 }
258 /******************************************************************************
259  * Extracts from a [HKEY\some\key\path] type of line the key name (what starts 
260  * after the first '\' and end before the ']'
261  */
262 LPSTR getRegKeyName(LPSTR lpLine) 
263 {
264   LPSTR keyNameBeg = NULL;
265   LPSTR keyNameEnd = NULL;
266   char  lpLineCopy[KEY_MAX_LEN];
267
268   if (lpLine == NULL)
269     return NULL;
270
271   strcpy(lpLineCopy, lpLine);
272
273   keyNameBeg  = strstr(lpLineCopy, "\\");  /* The key name start by '\' */
274   keyNameBeg++;                            /* but is not part of the key name */
275   keyNameEnd  = strstr(lpLineCopy, "]");   /* The key name end by ']' */
276   *keyNameEnd = '\0';                      /* Isolate the key name */
277  
278   currentKeyName = HeapAlloc(GetProcessHeap(), 0, strlen(keyNameBeg)+1);
279   if (currentKeyName != NULL)
280     strcpy(currentKeyName, keyNameBeg);
281  
282   return currentKeyName;
283 }
284
285 /******************************************************************************
286  * Extracts from a [HKEY/some/key/path] type of line the key class (what 
287  * starts after the '[' and ends before the first '\'
288  */
289 static HKEY getRegClass(LPSTR lpClass) 
290 {
291   LPSTR classNameEnd;
292   LPSTR classNameBeg;
293
294   char  lpClassCopy[KEY_MAX_LEN];
295   
296   if (lpClass == NULL)
297     return (HKEY)ERROR_INVALID_PARAMETER;
298
299   strcpy(lpClassCopy, lpClass);
300
301   classNameEnd  = strstr(lpClassCopy, "\\");  /* The class name end by '\' */
302   *classNameEnd = '\0';                       /* Isolate the class name */
303   classNameBeg  = &lpClassCopy[1];            /* Skip the '[' */
304   
305   if      (strcmp( classNameBeg, "HKEY_LOCAL_MACHINE") == IDENTICAL )
306     return  HKEY_LOCAL_MACHINE;
307   else if (strcmp( classNameBeg, "HKEY_USERS") == IDENTICAL )
308     return  HKEY_USERS;
309   else if (strcmp( classNameBeg, "HKEY_CLASSES_ROOT") == IDENTICAL )
310     return  HKEY_CLASSES_ROOT;
311   else if (strcmp( classNameBeg, "HKEY_CURRENT_CONFIG") == IDENTICAL )
312     return  HKEY_CURRENT_CONFIG;
313   else if (strcmp( classNameBeg, "HKEY_CURRENT_USER") == IDENTICAL )
314     return  HKEY_CURRENT_USER;
315   else
316     return (HKEY)ERROR_INVALID_PARAMETER;
317 }
318
319 /******************************************************************************
320  * Returns an allocated buffer with a cleaned copy (removed the surrounding 
321  * dbl quotes) of the passed value.
322  */
323 static LPSTR getArg( LPSTR arg)
324 {
325   LPSTR tmp = NULL;
326   ULONG len;
327
328   if (arg == NULL)
329     return NULL;
330
331   /*
332    * Get rid of surrounding quotes
333    */
334   len = strlen(arg); 
335
336   if( arg[len-1] == '\"' ) arg[len-1] = '\0';
337   if( arg[0]     == '\"' ) arg++;
338
339   tmp = HeapAlloc(GetProcessHeap(), 0, strlen(arg)+1);
340   strcpy(tmp, arg);
341
342   return tmp;
343 }
344
345 /******************************************************************************
346  * Returns the index in the commands array of the command to process.
347  */
348 static INT getCommand(LPSTR commandName)
349 {
350   INT count;
351   for (count=0; count < COMMAND_COUNT; count++)
352     if ( strcmp(commandName, commandNames[count]) == IDENTICAL) 
353       return count;
354
355   return COMMAND_NOT_FOUND;
356 }
357
358 /******************************************************************************
359  * Converts a hex representation of a DWORD into a DWORD.
360  */
361 static DWORD convertHexToDWord(char *str, BYTE *buf)
362 {
363   char  *s        = str;  /* Pointer to current */
364   char  *b        = buf;  /* Pointer to result  */
365   ULONG strPos    = 0;    
366
367   memset(buf, 0, 4);
368
369   while (strPos < 4)  /* 8 byte in a DWORD */
370   {
371     char xbuf[3];
372     char wc;
373
374     memcpy(xbuf,s,2); xbuf[2]='\0';
375     sscanf(xbuf,"%02x",(UINT*)&wc);
376     *b++ =(unsigned char)wc;
377
378     s+=2;
379     strPos+=1;
380   }                                   
381
382   return 4; /* always 4 byte for the word */
383 }
384
385 /******************************************************************************
386  * Converts a hex buffer into a hex comma separated values 
387  */
388 static char* convertHexToHexCSV(BYTE *buf, ULONG bufLen)
389 {
390   char* str;
391   char* ptrStr;
392   BYTE* ptrBuf;
393
394   ULONG current = 0;
395
396   str    = HeapAlloc(GetProcessHeap(), 0, (bufLen+1)*2);
397   memset(str, 0, (bufLen+1)*2);
398   ptrStr = str;  /* Pointer to result  */
399   ptrBuf = buf;  /* Pointer to current */
400
401   while (current < bufLen)
402   {
403     BYTE bCur = ptrBuf[current++];
404     char res[3];
405
406     sprintf(res, "%02x", (unsigned int)*&bCur);
407     strcat(str, res);
408     strcat(str, ",");
409   }                                   
410
411   /* Get rid of the last comma */
412   str[strlen(str)-1] = '\0';
413   return str;
414 }
415
416 /******************************************************************************
417  * Converts a hex buffer into a DWORD string
418  */
419 static char* convertHexToDWORDStr(BYTE *buf, ULONG bufLen)
420 {
421   char* str;
422   char* ptrStr;
423   BYTE* ptrBuf;
424
425   ULONG current = 0;
426
427   str    = HeapAlloc(GetProcessHeap(), 0, (bufLen*2)+1);
428   memset(str, 0, (bufLen*2)+1);
429   ptrStr = str;  /* Pointer to result  */
430   ptrBuf = buf;  /* Pointer to current */
431
432   while (current < bufLen)
433   {
434     BYTE bCur = ptrBuf[current++];
435     char res[3];
436
437     sprintf(res, "%02x", (unsigned int)*&bCur);
438     strcat(str, res);
439   }                                   
440
441   /* Get rid of the last comma */
442   return str;
443 }
444 /******************************************************************************
445  * Converts a hex comma separated values list into a hex list.
446  */
447 static DWORD convertHexCSVToHex(char *str, BYTE *buf, ULONG bufLen)
448 {
449   char *s = str;  /* Pointer to current */
450   char *b = buf;  /* Pointer to result  */
451
452   ULONG strLen    = strlen(str);
453   ULONG strPos    = 0;
454   DWORD byteCount = 0;
455
456   memset(buf, 0, bufLen);
457
458   /*
459    * warn the user if we are here with a string longer than 2 bytes that does
460    * not contains ",".  It is more likely because the data is invalid.
461    */
462   if ( ( strlen(str) > 2) && ( strstr(str, ",") == NULL) )
463     printf("regapi: WARNING converting CSV hex stream with no comma, "
464            "input data seems invalid.\n");
465
466   while (strPos < strLen)
467   {
468     char xbuf[3];
469     char wc;
470
471     memcpy(xbuf,s,2); xbuf[3]='\0';
472     sscanf(xbuf,"%02x",(UINT*)&wc);
473     *b++ =(unsigned char)wc;
474
475     s+=3;
476     strPos+=3;
477     byteCount++;
478   }                                   
479
480   return byteCount;
481 }
482
483
484 /******************************************************************************
485  * Sets the value in argv[0] to the data in argv[1] for the currently 
486  * opened key.
487  */
488 static HRESULT setValue(LPSTR *argv)
489 {
490   HRESULT hRes;
491   DWORD   dwSize          = KEY_MAX_LEN;
492   DWORD   dwType          = 0;
493   DWORD   dwDataType;
494
495   LPSTR   lpsCurrentValue;
496
497   LPSTR   keyValue = argv[0];
498   LPSTR   keyData  = argv[1];
499
500   /* Make some checks */
501   if ( (keyValue == NULL) || (keyData == NULL) )
502     return ERROR_INVALID_PARAMETER;
503
504   lpsCurrentValue=HeapAlloc(GetProcessHeap(), 0,KEY_MAX_LEN);
505   /*
506    * Default registry values are encoded in the input stream as '@' but as 
507    * blank in the wine registry.
508    */
509   if( (keyValue[0] == '@') && (strlen(keyValue) == 1) )
510     keyValue[0] = '\0';
511
512   /* Get the data type stored into the value field */
513   dwDataType = getDataType(&keyData);
514     
515   memset(lpsCurrentValue, 0, KEY_MAX_LEN);
516   hRes = RegQueryValueExA(
517           currentKeyHandle, 
518           keyValue, 
519           NULL, 
520           &dwType, 
521           (LPBYTE)lpsCurrentValue, 
522           &dwSize);
523
524   while(hRes==ERROR_MORE_DATA){
525       dwSize+=KEY_MAX_LEN;
526       lpsCurrentValue=HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,lpsCurrentValue,dwSize);
527       hRes = RegQueryValueExA(currentKeyHandle,keyValue,NULL,&dwType,(LPBYTE)lpsCurrentValue,&dwSize);
528   }
529
530   if( ( strlen(lpsCurrentValue) == 0 ) ||  /* The value is not existing */
531       ( bForce ))         /* -force option */ 
532   { 
533     LPBYTE lpbData;
534     BYTE   convert[KEY_MAX_LEN];
535     DWORD  dwLen;
536
537     if ( dwDataType == REG_SZ )        /* no convertion for string */
538     {
539       dwLen   = strlen(keyData);
540       lpbData = keyData;
541     } 
542     else if (dwDataType == REG_DWORD)  /* Convert the dword types */
543     {
544       dwLen   = convertHexToDWord(keyData, convert);
545       lpbData = convert;
546     }
547     else                               /* Convert the hexadecimal types */
548     {
549       dwLen   = convertHexCSVToHex(keyData, convert, KEY_MAX_LEN);
550       lpbData = convert;
551     }
552
553     hRes = RegSetValueEx(
554             currentKeyHandle, 
555             keyValue,
556             0,                  /* Reserved */
557             dwDataType,
558             lpbData,
559             dwLen);
560   }
561   else
562   {
563     /* return the current value data into argv[1] */
564     if (argv[1] != NULL)
565     {
566       HeapFree(GetProcessHeap(), 0, argv[1]);
567       argv[1] = HeapAlloc(GetProcessHeap(), 0, dwSize+1);
568
569       if ( argv[1] != NULL ) {
570         strncpy(argv[1], lpsCurrentValue, dwSize);
571         argv[1][dwSize]='\0';
572     }
573     }
574
575     return KEY_VALUE_ALREADY_SET;
576   }
577   return hRes;
578 }
579
580
581 /******************************************************************************
582  * Open the key
583  */
584 static HRESULT openKey( LPSTR stdInput)
585 {
586   DWORD   dwDisp;  
587   HRESULT hRes;
588
589   /* Sanity checks */
590   if (stdInput == NULL) 
591     return ERROR_INVALID_PARAMETER;
592
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;
597
598   /* Get the key name */
599   currentKeyName = getRegKeyName(stdInput); /* Sets global variable */
600   if (currentKeyName == NULL)
601     return ERROR_INVALID_PARAMETER;
602     
603   hRes = RegCreateKeyEx( 
604           currentKeyClass,          /* Class     */
605           currentKeyName,           /* Sub Key   */
606           0,                        /* MUST BE 0 */
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           &currentKeyHandle,        /* result */
612           &dwDisp);                 /* disposition, REG_CREATED_NEW_KEY or
613                                                     REG_OPENED_EXISTING_KEY */
614
615   if (hRes == ERROR_SUCCESS)
616     bTheKeyIsOpen = TRUE;
617
618   return hRes;
619
620 }
621 /******************************************************************************
622  * This function is a wrapper for the setValue function.  It prepares the 
623  * land and clean the area once completed.
624  */
625 static void processSetValue(LPSTR cmdline)
626 {
627   LPSTR argv[SET_VALUE_MAX_ARGS];  /* args storage    */
628
629   LPSTR token         = NULL;      /* current token analized */
630   ULONG argCounter    = 0;         /* counter of args */
631   INT   counter;
632   HRESULT hRes = 0;
633
634   /*
635    * Init storage and parse the line
636    */
637   for (counter=0; counter<SET_VALUE_MAX_ARGS; counter++)
638     argv[counter]=NULL;
639
640   while( (token = strsep(&cmdline, setValueDelim[argCounter])) != NULL ) 
641   {
642     argv[argCounter++] = getArg(token);
643
644     if (argCounter == SET_VALUE_MAX_ARGS)
645       break;  /* Stop processing args no matter what */
646   }
647
648   hRes = setValue(argv);
649   if ( hRes == ERROR_SUCCESS ) 
650     printf(
651       "regapi: Value \"%s\" has been set to \"%s\" in key [%s]\n", 
652       argv[0], 
653       argv[1],
654       currentKeyName);
655
656   else if ( hRes == KEY_VALUE_ALREADY_SET ) 
657     printf(
658       "regapi: Value \"%s\" already set to \"%s\" in key [%s]\n", 
659       argv[0], 
660       argv[1], 
661       currentKeyName);
662   
663   else
664     printf("regapi: ERROR Key %s not created. Value: %s, Data: %s\n",
665       currentKeyName,
666       argv[0], 
667       argv[1]);
668     
669   /*
670    * Do some cleanup
671    */
672   for (counter=0; counter<argCounter; counter++)
673     if (argv[counter] != NULL)
674       HeapFree(GetProcessHeap(), 0, argv[counter]);
675 }
676
677 /******************************************************************************
678  * This function is a wrapper for the queryValue function.  It prepares the 
679  * land and clean the area once completed.
680  */
681 static void processQueryValue(LPSTR cmdline)
682 {
683   LPSTR   argv[QUERY_VALUE_MAX_ARGS];/* args storage    */
684   LPSTR   token      = NULL;         /* current token analized */
685   ULONG   argCounter = 0;            /* counter of args */
686   INT     counter;
687   HRESULT hRes       = 0;
688   LPSTR   keyValue   = NULL;
689   LPSTR   lpsRes     = NULL;
690
691   /*
692    * Init storage and parse the line
693    */
694   for (counter=0; counter<QUERY_VALUE_MAX_ARGS; counter++)
695     argv[counter]=NULL;
696
697   while( (token = strsep(&cmdline, queryValueDelim[argCounter])) != NULL ) 
698   {
699     argv[argCounter++] = getArg(token);
700
701     if (argCounter == QUERY_VALUE_MAX_ARGS)
702       break;  /* Stop processing args no matter what */
703   }
704
705   /* The value we look for is the first token on the line */
706   if ( argv[0] == NULL )
707     return; /* SHOULD NOT OCCURS */
708   else
709     keyValue = argv[0]; 
710
711   if( (keyValue[0] == '@') && (strlen(keyValue) == 1) ) 
712   {
713     LONG  lLen  = KEY_MAX_LEN;
714     CHAR*  lpsData=HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,KEY_MAX_LEN);
715     /* 
716      * We need to query the key default value
717      */
718     hRes = RegQueryValue(
719              currentKeyHandle, 
720              currentKeyName, 
721              (LPBYTE)lpsData,
722              &lLen);
723
724     if (hRes==ERROR_MORE_DATA) {
725         lpsData=HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,lpsData,lLen);
726         hRes = RegQueryValue(currentKeyHandle,currentKeyName,(LPBYTE)lpsData,&lLen);
727     }
728
729     if (hRes == ERROR_SUCCESS)
730     {
731       lpsRes = HeapAlloc( GetProcessHeap(), 0, lLen);
732       strncpy(lpsRes, lpsData, lLen);
733       lpsRes[lLen-1]='\0';
734     }
735   }
736   else 
737   {
738     DWORD  dwLen  = KEY_MAX_LEN;
739     BYTE*  lpbData=HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,KEY_MAX_LEN);
740     DWORD  dwType;
741     /* 
742      * We need to query a specific value for the key
743      */
744     hRes = RegQueryValueEx(
745              currentKeyHandle, 
746              keyValue, 
747              0, 
748              &dwType, 
749              (LPBYTE)lpbData, 
750              &dwLen);
751
752     if (hRes==ERROR_MORE_DATA) {
753         lpbData=HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,lpbData,dwLen);
754         hRes = RegQueryValueEx(currentKeyHandle,keyValue,NULL,&dwType,(LPBYTE)lpbData,&dwLen);
755     }
756
757     if (hRes == ERROR_SUCCESS)
758     {
759       /* 
760        * Convert the returned data to a displayable format
761        */
762       switch ( dwType )
763       {
764         case REG_SZ:
765         case REG_EXPAND_SZ:
766         {
767           lpsRes = HeapAlloc( GetProcessHeap(), 0, dwLen);
768           strncpy(lpsRes, lpbData, dwLen);
769           lpsRes[dwLen-1]='\0';
770           break;
771         }
772         case REG_DWORD:
773         {
774           lpsRes = convertHexToDWORDStr(lpbData, dwLen);
775           break;
776         }
777         default:
778         {
779           lpsRes = convertHexToHexCSV(lpbData, dwLen);
780           break;
781         }
782       } 
783     }
784
785     HeapFree(GetProcessHeap(), 0, lpbData);
786   }
787  
788  
789   if ( hRes == ERROR_SUCCESS ) 
790     printf(
791       "regapi: Value \"%s\" = \"%s\" in key [%s]\n", 
792       keyValue, 
793       lpsRes,
794       currentKeyName);
795
796   else
797     printf("regapi: ERROR Value \"%s\" not found. for key \"%s\"\n",
798       keyValue, 
799       currentKeyName);
800     
801   /*
802    * Do some cleanup
803    */
804   for (counter=0; counter<argCounter; counter++)
805     if (argv[counter] != NULL)
806       HeapFree(GetProcessHeap(), 0, argv[counter]);
807
808   if (lpsRes != NULL)
809     HeapFree(GetProcessHeap(), 0, lpsRes);
810
811 }
812
813 /******************************************************************************
814  * Close the currently opened key.
815  */
816 static void closeKey()
817 {
818   RegCloseKey(currentKeyHandle); 
819
820   HeapFree(GetProcessHeap(), 0, currentKeyName); /* Allocated by getKeyName */
821
822   bTheKeyIsOpen    = FALSE;
823
824   currentKeyName   = NULL;
825   currentKeyClass  = 0;
826   currentKeyHandle = 0;
827 }
828
829 /******************************************************************************
830  * This funtion is the main entry point to the setValue type of action.  It 
831  * receives the currently read line and dispatch the work depending on the 
832  * context.
833  */
834 static void doSetValue(LPSTR stdInput)
835 {
836   /* 
837    * We encoutered the end of the file, make sure we 
838    * close the opened key and exit
839    */ 
840   if (stdInput == NULL)             
841   {
842     if (bTheKeyIsOpen != FALSE) 
843       closeKey();                    
844
845     return;
846   }
847     
848   if      ( stdInput[0] == '[')      /* We are reading a new key */
849   {
850     if ( bTheKeyIsOpen != FALSE )      
851       closeKey();                    /* Close the previous key before */
852
853     if ( openKey(stdInput) != ERROR_SUCCESS )
854       printf ("regapi: doSetValue failed to open key %s\n", stdInput);
855   }
856   else if( ( bTheKeyIsOpen ) && 
857            (( stdInput[0] == '@') || /* reading a default @=data pair */
858             ( stdInput[0] == '\"'))) /* reading a new value=data pair */
859   {
860     processSetValue(stdInput);
861   }
862   else                               /* since we are assuming that the */
863   {                                  /* file format is valid we must   */ 
864     if ( bTheKeyIsOpen )             /* be reading a blank line which  */
865       closeKey();                    /* indicate end of this key processing */ 
866   }
867 }
868
869 /******************************************************************************
870  * This funtion is the main entry point to the queryValue type of action.  It 
871  * receives the currently read line and dispatch the work depending on the 
872  * context.
873  */
874 static void doQueryValue(LPSTR stdInput) { 
875   /* 
876    * We encoutered the end of the file, make sure we 
877    * close the opened key and exit
878    */ 
879   if (stdInput == NULL)             
880   {
881     if (bTheKeyIsOpen != FALSE) 
882       closeKey();                    
883
884     return;
885   }
886     
887   if      ( stdInput[0] == '[')      /* We are reading a new key */
888   {
889     if ( bTheKeyIsOpen != FALSE )      
890       closeKey();                    /* Close the previous key before */
891
892     if ( openKey(stdInput) != ERROR_SUCCESS )
893       printf ("regapi: doSetValue failed to open key %s\n", stdInput);
894   }
895   else if( ( bTheKeyIsOpen ) && 
896            (( stdInput[0] == '@') || /* reading a default @=data pair */
897             ( stdInput[0] == '\"'))) /* reading a new value=data pair */
898   {
899     processQueryValue(stdInput);
900   }
901   else                               /* since we are assuming that the */
902   {                                  /* file format is valid we must   */ 
903     if ( bTheKeyIsOpen )             /* be reading a blank line which  */
904       closeKey();                    /* indicate end of this key processing */ 
905   }
906 }
907
908 /******************************************************************************
909  * This funtion is the main entry point to the deletetValue type of action.  It 
910  * receives the currently read line and dispatch the work depending on the 
911  * context.
912  */
913 static void doDeleteValue(LPSTR line) { 
914   printf ("regapi: deleteValue not yet implemented\n");
915 }
916 /******************************************************************************
917  * This funtion is the main entry point to the deleteKey type of action.  It 
918  * receives the currently read line and dispatch the work depending on the 
919  * context.
920  */
921 static void doDeleteKey(LPSTR line)   { 
922   printf ("regapi: deleteKey not yet implemented\n");
923 }
924 /******************************************************************************
925  * This funtion is the main entry point to the createKey type of action.  It 
926  * receives the currently read line and dispatch the work depending on the 
927  * context.
928  */
929 static void doCreateKey(LPSTR line)   { 
930   printf ("regapi: createKey not yet implemented\n");
931 }
932
933 /******************************************************************************
934  * This funtion is the main entry point to the registerDLL action.  It 
935  * receives the currently read line, then loads and registers the requested DLLs
936  */
937 static void doRegisterDLL(LPSTR stdInput) { 
938   HMODULE theLib = 0;
939   UINT retVal = 0;
940
941   /* Check for valid input */
942   if (stdInput == NULL)             
943     return;
944
945   /* Load and register the library, then free it */
946   theLib = LoadLibrary(stdInput);
947   if (theLib)
948   {
949     FARPROC lpfnDLLRegProc = GetProcAddress(theLib, "DllRegisterServer");
950     if (lpfnDLLRegProc)
951       retVal = (*lpfnDLLRegProc)();
952     else
953       printf("regapi: Couldn't find DllRegisterServer proc in '%s'.\n", stdInput);
954
955     if (retVal != S_OK)
956       printf("regapi: DLLRegisterServer error 0x%x in '%s'.\n", retVal, stdInput);      
957
958     FreeLibrary(theLib);
959   }
960   else
961   {
962     printf("regapi: Could not load DLL '%s'.\n", stdInput); 
963   }
964 }
965
966 /******************************************************************************
967  * This funtion is the main entry point to the unregisterDLL action.  It 
968  * receives the currently read line, then loads and unregisters the requested DLLs
969  */
970 static void doUnregisterDLL(LPSTR stdInput) { 
971   HMODULE theLib = 0;
972   UINT retVal = 0;
973
974   /* Check for valid input */
975   if (stdInput == NULL)             
976     return;
977
978   /* Load and unregister the library, then free it */
979   theLib = LoadLibrary(stdInput);
980   if (theLib)
981   {
982     FARPROC lpfnDLLRegProc = GetProcAddress(theLib, "DllUnregisterServer");
983     if (lpfnDLLRegProc)
984       retVal = (*lpfnDLLRegProc)();
985     else
986       printf("regapi: Couldn't find DllUnregisterServer proc in '%s'.\n", stdInput);
987
988     if (retVal != S_OK)
989       printf("regapi: DLLUnregisterServer error 0x%x in '%s'.\n", retVal, stdInput);      
990
991     FreeLibrary(theLib);
992   }
993   else
994   {
995     printf("regapi: Could not load DLL '%s'.\n", stdInput); 
996   }
997 }
998
999 /******************************************************************************
1000  * MAIN - The main simply validate the first parameter (command to perform)
1001  *        It then read the STDIN lines by lines forwarding their processing
1002  *        to the appropriate method.
1003  */
1004 int PASCAL WinMain (HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show)
1005 {
1006   LPSTR  token          = NULL;  /* current token analized */
1007   LPSTR  stdInput       = NULL;  /* line read from stdin */
1008   INT    cmdIndex       = -1;    /* index of the command in array */
1009   LPSTR nextLine        = NULL;
1010   ULONG  currentSize    = STDIN_MAX_LEN;
1011
1012   stdInput = HeapAlloc(GetProcessHeap(), 0, STDIN_MAX_LEN); 
1013   nextLine = HeapAlloc(GetProcessHeap(), 0, STDIN_MAX_LEN);
1014
1015   if (stdInput == NULL || nextLine== NULL)
1016     return NOT_ENOUGH_MEMORY;
1017
1018   /*
1019    * get the command, should be the first arg (modify cmdLine)
1020    */ 
1021   token = strsep(&cmdline, " "); 
1022   if (token != NULL) 
1023   {
1024     cmdIndex = getCommand(token);
1025     if (cmdIndex == COMMAND_NOT_FOUND)
1026     {
1027       printf("regapi: Command \"%s\" is not supported.\n", token);
1028       printf(helpText);
1029       return COMMAND_NOT_SUPPORTED;
1030     }
1031   }    
1032   else
1033   {
1034     printf(
1035       "regapi: The first item on the command line must be the command name.\n");
1036     printf(helpText);
1037     return COMMAND_NOT_SUPPORTED;
1038   }
1039
1040   /* 
1041    * check to see weather we force the action 
1042    * (meaning differ depending on the command performed)
1043    */
1044   if ( cmdline != NULL ) /* will be NULL if '-force' is not provided */
1045     if ( strstr(cmdline, "-force") != NULL )
1046       bForce = TRUE;
1047
1048   printf("Processing stdin...\n");
1049
1050   while ( TRUE )
1051   {
1052     /* 
1053      * read a line
1054      */
1055       ULONG curSize=STDIN_MAX_LEN;
1056       char* s=NULL;
1057    
1058       while((NULL!=(stdInput=fgets(stdInput,curSize,stdin))) && (NULL==(s=strchr(stdInput,'\n'))) ){
1059           fseek(stdin,-curSize,SEEK_CUR+1);
1060           stdInput=HeapReAlloc(GetProcessHeap(), 0,stdInput,curSize+=STDIN_MAX_LEN);
1061       }
1062     /* 
1063      * Make some handy generic stuff here... 
1064      */
1065     if ( stdInput != NULL )
1066     {
1067       stdInput[strlen(stdInput) -1] = '\0'; /* get rid of new line */
1068
1069       if( stdInput[0] == '#' )              /* this is a comment, skip */
1070         continue;
1071
1072       while( stdInput[strlen(stdInput) -1] == '\\' ){ /* a '\' char in the end of the current line means  */
1073                                                       /* that this line is not complete and we have to get */
1074           stdInput[strlen(stdInput) -1]= '\0';        /* the rest in the next lines */
1075
1076           nextLine = fgets(nextLine, STDIN_MAX_LEN, stdin);
1077
1078           nextLine[strlen(nextLine)-1] = '\0';
1079
1080           if ( (strlen(stdInput)+strlen(nextLine)) > currentSize){
1081
1082               stdInput=HeapReAlloc(GetProcessHeap(),0,stdInput,strlen(stdInput)+STDIN_MAX_LEN);
1083
1084               currentSize+=STDIN_MAX_LEN;
1085     }
1086
1087           strcat(stdInput,nextLine+2);
1088       }
1089     }
1090
1091     /* 
1092      * We process every lines even the NULL (last) line, to indicate the 
1093      * end of the processing to the specific process.
1094      */
1095     commandAPIs[cmdIndex](stdInput);       
1096
1097     if (stdInput == NULL)  /* EOF encountered */
1098       break;
1099   }
1100
1101 #if 0 
1102   /* 
1103    * Save the registry only if it was modified 
1104    */
1105  if ( commandSaveRegistry[cmdIndex] != FALSE )
1106        SHELL_SaveRegistry();
1107 #endif
1108   HeapFree(GetProcessHeap(), 0, nextLine);
1109
1110   HeapFree(GetProcessHeap(), 0, stdInput);
1111
1112   return SUCCESS;
1113 }