hidclass.sys: Add hidclass.sys.
[wine.git] / programs / reg / reg.c
blob4ec25bc133b257f61af70fcac2ff474c5e6c3017
1 /*
2 * Copyright 2008 Andrew Riedi
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 #include <windows.h>
20 #include <wine/unicode.h>
21 #include "reg.h"
23 #define ARRAY_SIZE(A) (sizeof(A)/sizeof(*A))
25 static const WCHAR type_none[] = {'R','E','G','_','N','O','N','E',0};
26 static const WCHAR type_sz[] = {'R','E','G','_','S','Z',0};
27 static const WCHAR type_expand_sz[] = {'R','E','G','_','E','X','P','A','N','D','_','S','Z',0};
28 static const WCHAR type_binary[] = {'R','E','G','_','B','I','N','A','R','Y',0};
29 static const WCHAR type_dword[] = {'R','E','G','_','D','W','O','R','D',0};
30 static const WCHAR type_dword_le[] = {'R','E','G','_','D','W','O','R','D','_','L','I','T','T','L','E','_','E','N','D','I','A','N',0};
31 static const WCHAR type_dword_be[] = {'R','E','G','_','D','W','O','R','D','_','B','I','G','_','E','N','D','I','A','N',0};
32 static const WCHAR type_multi_sz[] = {'R','E','G','_','M','U','L','T','I','_','S','Z',0};
34 static const struct
36 DWORD type;
37 const WCHAR *name;
39 type_rels[] =
41 {REG_NONE, type_none},
42 {REG_SZ, type_sz},
43 {REG_EXPAND_SZ, type_expand_sz},
44 {REG_BINARY, type_binary},
45 {REG_DWORD, type_dword},
46 {REG_DWORD_LITTLE_ENDIAN, type_dword_le},
47 {REG_DWORD_BIG_ENDIAN, type_dword_be},
48 {REG_MULTI_SZ, type_multi_sz},
51 static int reg_printfW(const WCHAR *msg, ...)
53 va_list va_args;
54 int wlen;
55 DWORD count, ret;
56 WCHAR msg_buffer[8192];
58 va_start(va_args, msg);
59 vsnprintfW(msg_buffer, 8192, msg, va_args);
60 va_end(va_args);
62 wlen = lstrlenW(msg_buffer);
63 ret = WriteConsoleW(GetStdHandle(STD_OUTPUT_HANDLE), msg_buffer, wlen, &count, NULL);
64 if (!ret)
66 DWORD len;
67 char *msgA;
69 /* On Windows WriteConsoleW() fails if the output is redirected. So fall
70 * back to WriteFile(), assuming the console encoding is still the right
71 * one in that case.
73 len = WideCharToMultiByte(GetConsoleOutputCP(), 0, msg_buffer, wlen,
74 NULL, 0, NULL, NULL);
75 msgA = HeapAlloc(GetProcessHeap(), 0, len * sizeof(char));
76 if (!msgA)
77 return 0;
79 WideCharToMultiByte(GetConsoleOutputCP(), 0, msg_buffer, wlen, msgA, len,
80 NULL, NULL);
81 WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), msgA, len, &count, FALSE);
82 HeapFree(GetProcessHeap(), 0, msgA);
85 return count;
88 static int reg_message(int msg)
90 static const WCHAR formatW[] = {'%','s',0};
91 WCHAR msg_buffer[8192];
93 LoadStringW(GetModuleHandleW(NULL), msg, msg_buffer,
94 sizeof(msg_buffer)/sizeof(WCHAR));
95 return reg_printfW(formatW, msg_buffer);
98 static int reg_StrCmpNIW(LPCWSTR str, LPCWSTR comp, int len)
100 int i;
102 for (i = 0; i < len; i++)
104 if (!str[i])
106 len = i + 1;
107 break;
111 return CompareStringW(CP_ACP, NORM_IGNORECASE, str, len, comp, len) - CSTR_EQUAL;
114 static HKEY get_rootkey(LPWSTR key)
116 static const WCHAR szHKLM[] = {'H','K','L','M',0};
117 static const WCHAR szHKEY_LOCAL_MACHINE[] = {'H','K','E','Y','_','L','O','C','A','L','_','M','A','C','H','I','N','E',0};
118 static const WCHAR szHKCU[] = {'H','K','C','U',0};
119 static const WCHAR szHKEY_CURRENT_USER[] = {'H','K','E','Y','_','C','U','R','R','E','N','T','_','U','S','E','R',0};
120 static const WCHAR szHKCR[] = {'H','K','C','R',0};
121 static const WCHAR szHKEY_CLASSES_ROOT[] = {'H','K','E','Y','_','C','L','A','S','S','E','S','_','R','O','O','T',0};
122 static const WCHAR szHKU[] = {'H','K','U',0};
123 static const WCHAR szHKEY_USERS[] = {'H','K','E','Y','_','U','S','E','R','S',0};
124 static const WCHAR szHKCC[] = {'H','K','C','C',0};
125 static const WCHAR szHKEY_CURRENT_CONFIG[] = {'H','K','E','Y','_','C','U','R','R','E','N','T','_','C','O','N','F','I','G',0};
127 if (!reg_StrCmpNIW(key, szHKLM, 4) ||
128 !reg_StrCmpNIW(key, szHKEY_LOCAL_MACHINE, 18))
129 return HKEY_LOCAL_MACHINE;
130 else if (!reg_StrCmpNIW(key, szHKCU, 4) ||
131 !reg_StrCmpNIW(key, szHKEY_CURRENT_USER, 17))
132 return HKEY_CURRENT_USER;
133 else if (!reg_StrCmpNIW(key, szHKCR, 4) ||
134 !reg_StrCmpNIW(key, szHKEY_CLASSES_ROOT, 17))
135 return HKEY_CLASSES_ROOT;
136 else if (!reg_StrCmpNIW(key, szHKU, 3) ||
137 !reg_StrCmpNIW(key, szHKEY_USERS, 10))
138 return HKEY_USERS;
139 else if (!reg_StrCmpNIW(key, szHKCC, 4) ||
140 !reg_StrCmpNIW(key, szHKEY_CURRENT_CONFIG, 19))
141 return HKEY_CURRENT_CONFIG;
142 else return NULL;
145 static DWORD wchar_get_type(const WCHAR *type_name)
147 DWORD i;
149 if (!type_name)
150 return REG_SZ;
152 for (i = 0; i < ARRAY_SIZE(type_rels); i++)
154 if (!strcmpiW(type_rels[i].name, type_name))
155 return type_rels[i].type;
158 return ~0u;
161 static LPBYTE get_regdata(LPWSTR data, DWORD reg_type, WCHAR separator, DWORD *reg_count)
163 LPBYTE out_data = NULL;
164 *reg_count = 0;
166 switch (reg_type)
168 case REG_SZ:
170 *reg_count = (lstrlenW(data) + 1) * sizeof(WCHAR);
171 out_data = HeapAlloc(GetProcessHeap(),0,*reg_count);
172 lstrcpyW((LPWSTR)out_data,data);
173 break;
175 case REG_DWORD:
177 LPWSTR rest;
178 DWORD val;
179 val = strtolW(data, &rest, 0);
180 if (rest == data) {
181 static const WCHAR nonnumber[] = {'E','r','r','o','r',':',' ','/','d',' ','r','e','q','u','i','r','e','s',' ','n','u','m','b','e','r','.','\n',0};
182 reg_printfW(nonnumber);
183 break;
185 *reg_count = sizeof(DWORD);
186 out_data = HeapAlloc(GetProcessHeap(),0,*reg_count);
187 ((LPDWORD)out_data)[0] = val;
188 break;
190 default:
192 static const WCHAR unhandled[] = {'U','n','h','a','n','d','l','e','d',' ','T','y','p','e',' ','0','x','%','x',' ',' ','d','a','t','a',' ','%','s','\n',0};
193 reg_printfW(unhandled, reg_type,data);
197 return out_data;
200 static BOOL sane_path(const WCHAR *key)
202 unsigned int i = strlenW(key);
204 if (i < 3 || (key[i - 1] == '\\' && key[i - 2] == '\\'))
206 reg_message(STRING_INVALID_KEY);
207 return FALSE;
210 if (key[0] == '\\' && key[1] == '\\' && key[2] != '\\')
212 reg_message(STRING_NO_REMOTE);
213 return FALSE;
216 return TRUE;
219 static int reg_add(WCHAR *key_name, WCHAR *value_name, BOOL value_empty,
220 WCHAR *type, WCHAR separator, WCHAR *data, BOOL force)
222 static const WCHAR stubW[] = {'A','D','D',' ','-',' ','%','s',
223 ' ','%','s',' ','%','d',' ','%','s',' ','%','s',' ','%','d','\n',0};
224 LPWSTR p;
225 HKEY root,subkey;
227 reg_printfW(stubW, key_name, value_name, value_empty, type, data, force);
229 if (!sane_path(key_name))
230 return 1;
232 p = strchrW(key_name,'\\');
233 if (!p)
235 reg_message(STRING_INVALID_KEY);
236 return 1;
238 p++;
240 root = get_rootkey(key_name);
241 if (!root)
243 reg_message(STRING_INVALID_KEY);
244 return 1;
247 if(RegCreateKeyW(root,p,&subkey)!=ERROR_SUCCESS)
249 reg_message(STRING_INVALID_KEY);
250 return 1;
253 if (value_name || data)
255 DWORD reg_type;
256 DWORD reg_count = 0;
257 BYTE* reg_data = NULL;
259 if (!force)
261 if (RegQueryValueW(subkey,value_name,NULL,NULL)==ERROR_SUCCESS)
263 /* FIXME: Prompt for overwrite */
267 reg_type = wchar_get_type(type);
268 if (reg_type == ~0u)
270 RegCloseKey(subkey);
271 reg_message(STRING_UNSUPPORTED_TYPE);
272 return 1;
275 if (data)
276 reg_data = get_regdata(data,reg_type,separator,&reg_count);
278 RegSetValueExW(subkey,value_name,0,reg_type,reg_data,reg_count);
279 HeapFree(GetProcessHeap(),0,reg_data);
282 RegCloseKey(subkey);
283 reg_message(STRING_SUCCESS);
285 return 0;
288 static int reg_delete(WCHAR *key_name, WCHAR *value_name, BOOL value_empty,
289 BOOL value_all, BOOL force)
291 LPWSTR p;
292 HKEY root,subkey;
294 static const WCHAR stubW[] = {'D','E','L','E','T','E',
295 ' ','-',' ','%','s',' ','%','s',' ','%','d',' ','%','d',' ','%','d','\n'
296 ,0};
297 reg_printfW(stubW, key_name, value_name, value_empty, value_all, force);
299 if (!sane_path(key_name))
300 return 1;
302 p = strchrW(key_name,'\\');
303 if (!p)
305 reg_message(STRING_INVALID_KEY);
306 return 1;
308 p++;
310 root = get_rootkey(key_name);
311 if (!root)
313 reg_message(STRING_INVALID_KEY);
314 return 1;
317 if (value_name && value_empty)
319 reg_message(STRING_INVALID_CMDLINE);
320 return 1;
323 if (value_empty && value_all)
325 reg_message(STRING_INVALID_CMDLINE);
326 return 1;
329 if (!force)
331 /* FIXME: Prompt for delete */
334 /* Delete subtree only if no /v* option is given */
335 if (!value_name && !value_empty && !value_all)
337 if (RegDeleteTreeW(root,p)!=ERROR_SUCCESS)
339 reg_message(STRING_CANNOT_FIND);
340 return 1;
342 reg_message(STRING_SUCCESS);
343 return 0;
346 if(RegOpenKeyW(root,p,&subkey)!=ERROR_SUCCESS)
348 reg_message(STRING_CANNOT_FIND);
349 return 1;
352 if (value_all)
354 LPWSTR szValue;
355 DWORD maxValue;
356 DWORD count;
357 LONG rc;
359 rc = RegQueryInfoKeyW(subkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
360 &maxValue, NULL, NULL, NULL);
361 if (rc != ERROR_SUCCESS)
363 /* FIXME: failure */
364 RegCloseKey(subkey);
365 return 1;
367 maxValue++;
368 szValue = HeapAlloc(GetProcessHeap(),0,maxValue*sizeof(WCHAR));
370 while (1)
372 count = maxValue;
373 rc = RegEnumValueW(subkey, 0, szValue, &count, NULL, NULL, NULL, NULL);
374 if (rc == ERROR_SUCCESS)
376 rc = RegDeleteValueW(subkey, szValue);
377 if (rc != ERROR_SUCCESS)
378 break;
380 else break;
382 if (rc != ERROR_SUCCESS)
384 /* FIXME delete failed */
387 else if (value_name)
389 if (RegDeleteValueW(subkey,value_name) != ERROR_SUCCESS)
391 RegCloseKey(subkey);
392 reg_message(STRING_CANNOT_FIND);
393 return 1;
396 else if (value_empty)
398 RegSetValueExW(subkey,NULL,0,REG_SZ,NULL,0);
401 RegCloseKey(subkey);
402 reg_message(STRING_SUCCESS);
403 return 0;
406 static int reg_query(WCHAR *key_name, WCHAR *value_name, BOOL value_empty,
407 BOOL subkey)
409 static const WCHAR stubW[] = {'S','T','U','B',' ','Q','U','E','R','Y',' ',
410 '-',' ','%','s',' ','%','s',' ','%','d',' ','%','d','\n',0};
411 reg_printfW(stubW, key_name, value_name, value_empty, subkey);
413 return 1;
416 int wmain(int argc, WCHAR *argvW[])
418 int i;
420 static const WCHAR addW[] = {'a','d','d',0};
421 static const WCHAR deleteW[] = {'d','e','l','e','t','e',0};
422 static const WCHAR queryW[] = {'q','u','e','r','y',0};
423 static const WCHAR slashDW[] = {'/','d',0};
424 static const WCHAR slashFW[] = {'/','f',0};
425 static const WCHAR slashHW[] = {'/','h',0};
426 static const WCHAR slashSW[] = {'/','s',0};
427 static const WCHAR slashTW[] = {'/','t',0};
428 static const WCHAR slashVW[] = {'/','v',0};
429 static const WCHAR slashVAW[] = {'/','v','a',0};
430 static const WCHAR slashVEW[] = {'/','v','e',0};
431 static const WCHAR slashHelpW[] = {'/','?',0};
433 if (argc < 2 || !lstrcmpW(argvW[1], slashHelpW)
434 || !lstrcmpiW(argvW[1], slashHW))
436 reg_message(STRING_USAGE);
437 return 0;
440 if (!lstrcmpiW(argvW[1], addW))
442 WCHAR *key_name, *value_name = NULL, *type = NULL, separator = '\0', *data = NULL;
443 BOOL value_empty = FALSE, force = FALSE;
445 if (argc < 3)
447 reg_message(STRING_INVALID_CMDLINE);
448 return 1;
450 else if (argc == 3 && (!lstrcmpW(argvW[2], slashHelpW) ||
451 !lstrcmpiW(argvW[2], slashHW)))
453 reg_message(STRING_ADD_USAGE);
454 return 0;
457 key_name = argvW[2];
458 for (i = 1; i < argc; i++)
460 if (!lstrcmpiW(argvW[i], slashVW))
461 value_name = argvW[++i];
462 else if (!lstrcmpiW(argvW[i], slashVEW))
463 value_empty = TRUE;
464 else if (!lstrcmpiW(argvW[i], slashTW))
465 type = argvW[++i];
466 else if (!lstrcmpiW(argvW[i], slashSW))
467 separator = argvW[++i][0];
468 else if (!lstrcmpiW(argvW[i], slashDW))
469 data = argvW[++i];
470 else if (!lstrcmpiW(argvW[i], slashFW))
471 force = TRUE;
473 return reg_add(key_name, value_name, value_empty, type, separator,
474 data, force);
476 else if (!lstrcmpiW(argvW[1], deleteW))
478 WCHAR *key_name, *value_name = NULL;
479 BOOL value_empty = FALSE, value_all = FALSE, force = FALSE;
481 if (argc < 3)
483 reg_message(STRING_INVALID_CMDLINE);
484 return 1;
486 else if (argc == 3 && (!lstrcmpW(argvW[2], slashHelpW) ||
487 !lstrcmpiW(argvW[2], slashHW)))
489 reg_message(STRING_DELETE_USAGE);
490 return 0;
493 key_name = argvW[2];
494 for (i = 1; i < argc; i++)
496 if (!lstrcmpiW(argvW[i], slashVW))
497 value_name = argvW[++i];
498 else if (!lstrcmpiW(argvW[i], slashVEW))
499 value_empty = TRUE;
500 else if (!lstrcmpiW(argvW[i], slashVAW))
501 value_all = TRUE;
502 else if (!lstrcmpiW(argvW[i], slashFW))
503 force = TRUE;
505 return reg_delete(key_name, value_name, value_empty, value_all, force);
507 else if (!lstrcmpiW(argvW[1], queryW))
509 WCHAR *key_name, *value_name = NULL;
510 BOOL value_empty = FALSE, subkey = FALSE;
512 if (argc < 3)
514 reg_message(STRING_INVALID_CMDLINE);
515 return 1;
517 else if (argc == 3 && (!lstrcmpW(argvW[2], slashHelpW) ||
518 !lstrcmpiW(argvW[2], slashHW)))
520 reg_message(STRING_QUERY_USAGE);
521 return 0;
524 key_name = argvW[2];
525 for (i = 1; i < argc; i++)
527 if (!lstrcmpiW(argvW[i], slashVW))
528 value_name = argvW[++i];
529 else if (!lstrcmpiW(argvW[i], slashVEW))
530 value_empty = TRUE;
531 else if (!lstrcmpiW(argvW[i], slashSW))
532 subkey = TRUE;
534 return reg_query(key_name, value_name, value_empty, subkey);
536 else
538 reg_message(STRING_INVALID_CMDLINE);
539 return 1;