ddraw/tests: Use compare_uint() in compare_float() instead of abs().
[wine.git] / programs / reg / query.c
blobc1d08541c6858f40f17d43a3b0780d05cf17dbb6
1 /*
2 * Copyright 2016-2017, 2021 Hugh McMaster
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 <stdio.h>
20 #include "reg.h"
22 static const WCHAR *reg_type_to_wchar(DWORD type)
24 int i, array_size = ARRAY_SIZE(type_rels);
26 for (i = 0; i < array_size; i++)
28 if (type == type_rels[i].type)
29 return type_rels[i].name;
32 return NULL;
35 static WCHAR *reg_data_to_wchar(DWORD type, const BYTE *src, DWORD size_bytes)
37 WCHAR *buffer = NULL;
38 int i;
40 switch (type)
42 case REG_SZ:
43 case REG_EXPAND_SZ:
44 buffer = malloc(size_bytes);
45 lstrcpyW(buffer, (WCHAR *)src);
46 break;
47 case REG_NONE:
48 case REG_BINARY:
50 WCHAR *ptr;
52 buffer = malloc((size_bytes * 2 + 1) * sizeof(WCHAR));
54 if (!size_bytes)
56 *buffer = 0;
57 break;
60 ptr = buffer;
62 for (i = 0; i < size_bytes; i++)
63 ptr += swprintf(ptr, 3, L"%02X", src[i]);
64 break;
66 case REG_DWORD:
67 /* case REG_DWORD_LITTLE_ENDIAN: */
68 case REG_DWORD_BIG_ENDIAN:
70 const int zero_x_dword = 10;
72 buffer = malloc((zero_x_dword + 1) * sizeof(WCHAR));
73 swprintf(buffer, zero_x_dword + 1, L"0x%x", *(DWORD *)src);
74 break;
76 case REG_MULTI_SZ:
78 const int two_wchars = 2 * sizeof(WCHAR);
79 DWORD tmp_size;
80 const WCHAR *tmp = (const WCHAR *)src;
81 int len, destindex;
83 if (size_bytes <= two_wchars)
85 buffer = malloc(sizeof(WCHAR));
86 *buffer = 0;
87 return buffer;
90 tmp_size = size_bytes - two_wchars; /* exclude both null terminators */
91 buffer = malloc(tmp_size * 2 + sizeof(WCHAR));
92 len = tmp_size / sizeof(WCHAR);
94 for (i = 0, destindex = 0; i < len; i++, destindex++)
96 if (tmp[i])
97 buffer[destindex] = tmp[i];
98 else
100 buffer[destindex++] = '\\';
101 buffer[destindex] = '0';
104 buffer[destindex] = 0;
105 break;
108 return buffer;
111 static const WCHAR *newlineW = L"\n";
113 static void output_value(const WCHAR *value_name, DWORD type, BYTE *data, DWORD data_size)
115 static const WCHAR *fmt = L" %1";
116 WCHAR defval[32];
117 WCHAR *reg_data;
119 if (value_name && value_name[0])
120 output_string(fmt, value_name);
121 else
123 LoadStringW(GetModuleHandleW(NULL), STRING_DEFAULT_VALUE, defval, ARRAY_SIZE(defval));
124 output_string(fmt, defval);
126 output_string(fmt, reg_type_to_wchar(type));
128 if (data)
130 reg_data = reg_data_to_wchar(type, data, data_size);
131 output_string(fmt, reg_data);
132 free(reg_data);
134 else
136 LoadStringW(GetModuleHandleW(NULL), STRING_VALUE_NOT_SET, defval, ARRAY_SIZE(defval));
137 output_string(fmt, defval);
139 output_string(newlineW);
142 static unsigned int num_values_found = 0;
143 static REGSAM sam = 0;
145 static int query_value(HKEY hkey, WCHAR *value_name, WCHAR *path, BOOL recurse)
147 LONG rc;
148 DWORD max_data_bytes = 2048, data_size;
149 DWORD subkey_len;
150 DWORD type, path_len, i;
151 BYTE *data;
152 static const WCHAR *fmt = L"%1\n";
153 WCHAR *subkey_name, *subkey_path;
154 HKEY subkey;
156 data = malloc(max_data_bytes);
158 for (;;)
160 data_size = max_data_bytes;
161 rc = RegQueryValueExW(hkey, value_name, NULL, &type, data, &data_size);
162 if (rc == ERROR_MORE_DATA)
164 max_data_bytes = data_size;
165 data = realloc(data, max_data_bytes);
167 else break;
170 if (rc == ERROR_SUCCESS)
172 output_string(fmt, path);
173 output_value(value_name, type, data, data_size);
174 output_string(newlineW);
175 num_values_found++;
178 free(data);
180 if (!recurse)
182 if (rc == ERROR_FILE_NOT_FOUND)
184 if (value_name && *value_name)
186 output_message(STRING_VALUE_NONEXIST);
187 return 1;
189 output_string(fmt, path);
190 output_value(NULL, REG_SZ, NULL, 0);
192 return 0;
195 subkey_name = malloc(MAX_SUBKEY_LEN * sizeof(WCHAR));
197 path_len = lstrlenW(path);
199 i = 0;
200 for (;;)
202 subkey_len = MAX_SUBKEY_LEN;
203 rc = RegEnumKeyExW(hkey, i, subkey_name, &subkey_len, NULL, NULL, NULL, NULL);
204 if (rc == ERROR_SUCCESS)
206 subkey_path = build_subkey_path(path, path_len, subkey_name, subkey_len);
207 if (!RegOpenKeyExW(hkey, subkey_name, 0, KEY_READ|sam, &subkey))
209 query_value(subkey, value_name, subkey_path, recurse);
210 RegCloseKey(subkey);
212 free(subkey_path);
213 i++;
215 else break;
218 free(subkey_name);
219 return 0;
222 static int query_all(HKEY hkey, WCHAR *path, BOOL recurse, BOOL recursing)
224 LONG rc;
225 DWORD num_subkeys, num_values;
226 DWORD max_value_len = 256, value_len;
227 DWORD max_data_bytes = 2048, data_size;
228 DWORD subkey_len;
229 DWORD i, type, path_len;
230 WCHAR *value_name, *subkey_name, *subkey_path;
231 BYTE *data;
232 HKEY subkey;
234 rc = RegQueryInfoKeyW(hkey, NULL, NULL, NULL, &num_subkeys, NULL,
235 NULL, &num_values, NULL, NULL, NULL, NULL);
236 if (rc) return 1;
238 if (num_values || recursing)
239 output_string(L"%1\n", path);
241 value_name = malloc(max_value_len * sizeof(WCHAR));
242 data = malloc(max_data_bytes);
244 i = 0;
245 for (;;)
247 value_len = max_value_len;
248 data_size = max_data_bytes;
249 rc = RegEnumValueW(hkey, i, value_name, &value_len, NULL, &type, data, &data_size);
250 if (rc == ERROR_SUCCESS)
252 output_value(value_name, type, data, data_size);
253 i++;
255 else if (rc == ERROR_MORE_DATA)
257 if (data_size > max_data_bytes)
259 max_data_bytes = data_size;
260 data = realloc(data, max_data_bytes);
262 else
264 max_value_len *= 2;
265 value_name = realloc(value_name, max_value_len * sizeof(WCHAR));
268 else break;
271 free(data);
272 free(value_name);
274 if (i || recursing)
275 output_string(newlineW);
277 if (!num_subkeys)
278 return 0;
280 subkey_name = malloc(MAX_SUBKEY_LEN * sizeof(WCHAR));
282 path_len = lstrlenW(path);
284 i = 0;
285 for (;;)
287 subkey_len = MAX_SUBKEY_LEN;
288 rc = RegEnumKeyExW(hkey, i, subkey_name, &subkey_len, NULL, NULL, NULL, NULL);
289 if (rc == ERROR_SUCCESS)
291 if (recurse)
293 subkey_path = build_subkey_path(path, path_len, subkey_name, subkey_len);
294 if (!RegOpenKeyExW(hkey, subkey_name, 0, KEY_READ|sam, &subkey))
296 query_all(subkey, subkey_path, recurse, TRUE);
297 RegCloseKey(subkey);
299 free(subkey_path);
301 else output_string(L"%1\\%2\n", path, subkey_name);
302 i++;
304 else break;
307 free(subkey_name);
308 return 0;
311 static int run_query(HKEY root, WCHAR *path, WCHAR *key_name, WCHAR *value_name,
312 BOOL value_empty, BOOL recurse)
314 HKEY hkey;
315 int ret;
317 if (RegOpenKeyExW(root, path, 0, KEY_READ|sam, &hkey))
319 output_message(STRING_KEY_NONEXIST);
320 return 1;
323 output_string(newlineW);
325 if (value_name || value_empty)
327 ret = query_value(hkey, value_name, key_name, recurse);
328 if (recurse)
329 output_message(STRING_MATCHES_FOUND, num_values_found);
331 else
332 ret = query_all(hkey, key_name, recurse, FALSE);
334 RegCloseKey(hkey);
336 return ret;
339 int reg_query(int argc, WCHAR *argvW[])
341 HKEY root;
342 WCHAR *path, *key_name, *value_name = NULL;
343 BOOL value_empty = FALSE, recurse = FALSE;
344 int i;
346 if (!parse_registry_key(argvW[2], &root, &path))
347 return 1;
349 for (i = 3; i < argc; i++)
351 WCHAR *str;
353 if (argvW[i][0] != '/' && argvW[i][0] != '-')
354 goto invalid;
356 str = &argvW[i][1];
358 if (!lstrcmpiW(str, L"ve"))
360 if (value_empty) goto invalid;
361 value_empty = TRUE;
362 continue;
364 else if (!lstrcmpiW(str, L"reg:32"))
366 if (sam & KEY_WOW64_32KEY) goto invalid;
367 sam |= KEY_WOW64_32KEY;
368 continue;
370 else if (!lstrcmpiW(str, L"reg:64"))
372 if (sam & KEY_WOW64_64KEY) goto invalid;
373 sam |= KEY_WOW64_64KEY;
374 continue;
376 else if (!str[0] || str[1])
377 goto invalid;
379 switch (towlower(*str))
381 case 'v':
382 if (value_name || !(value_name = argvW[++i]))
383 goto invalid;
384 break;
385 case 's':
386 if (recurse) goto invalid;
387 recurse = TRUE;
388 break;
389 default:
390 goto invalid;
394 if (value_name && value_empty)
395 goto invalid;
397 if (sam == (KEY_WOW64_32KEY|KEY_WOW64_64KEY))
398 goto invalid;
400 key_name = get_long_key(root, path);
402 return run_query(root, path, key_name, value_name, value_empty, recurse);
404 invalid:
405 output_message(STRING_INVALID_SYNTAX);
406 output_message(STRING_FUNC_HELP, wcsupr(argvW[1]));
407 return 1;