reg: Print a new line when recursing and the current key has no registry values.
[wine.git] / programs / reg / query.c
blob66e545486884f4b36d7d02723bf451caeb90aade
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));
53 ptr = buffer;
54 for (i = 0; i < size_bytes; i++)
55 ptr += swprintf(ptr, 3, L"%02X", src[i]);
56 break;
58 case REG_DWORD:
59 /* case REG_DWORD_LITTLE_ENDIAN: */
60 case REG_DWORD_BIG_ENDIAN:
62 const int zero_x_dword = 10;
64 buffer = malloc((zero_x_dword + 1) * sizeof(WCHAR));
65 swprintf(buffer, zero_x_dword + 1, L"0x%x", *(DWORD *)src);
66 break;
68 case REG_MULTI_SZ:
70 const int two_wchars = 2 * sizeof(WCHAR);
71 DWORD tmp_size;
72 const WCHAR *tmp = (const WCHAR *)src;
73 int len, destindex;
75 if (size_bytes <= two_wchars)
77 buffer = malloc(sizeof(WCHAR));
78 *buffer = 0;
79 return buffer;
82 tmp_size = size_bytes - two_wchars; /* exclude both null terminators */
83 buffer = malloc(tmp_size * 2 + sizeof(WCHAR));
84 len = tmp_size / sizeof(WCHAR);
86 for (i = 0, destindex = 0; i < len; i++, destindex++)
88 if (tmp[i])
89 buffer[destindex] = tmp[i];
90 else
92 buffer[destindex++] = '\\';
93 buffer[destindex] = '0';
96 buffer[destindex] = 0;
97 break;
100 return buffer;
103 static const WCHAR *newlineW = L"\n";
105 static void output_value(const WCHAR *value_name, DWORD type, BYTE *data, DWORD data_size)
107 static const WCHAR *fmt = L" %1";
108 WCHAR defval[32];
109 WCHAR *reg_data;
111 if (value_name && value_name[0])
112 output_string(fmt, value_name);
113 else
115 LoadStringW(GetModuleHandleW(NULL), STRING_DEFAULT_VALUE, defval, ARRAY_SIZE(defval));
116 output_string(fmt, defval);
118 output_string(fmt, reg_type_to_wchar(type));
120 if (data)
122 reg_data = reg_data_to_wchar(type, data, data_size);
123 output_string(fmt, reg_data);
124 free(reg_data);
126 else
128 LoadStringW(GetModuleHandleW(NULL), STRING_VALUE_NOT_SET, defval, ARRAY_SIZE(defval));
129 output_string(fmt, defval);
131 output_string(newlineW);
134 static unsigned int num_values_found = 0;
136 static int query_value(HKEY hkey, WCHAR *value_name, WCHAR *path, BOOL recurse)
138 LONG rc;
139 DWORD max_data_bytes = 2048, data_size;
140 DWORD subkey_len;
141 DWORD type, path_len, i;
142 BYTE *data;
143 static const WCHAR *fmt = L"%1\n";
144 WCHAR *subkey_name, *subkey_path;
145 HKEY subkey;
147 data = malloc(max_data_bytes);
149 for (;;)
151 data_size = max_data_bytes;
152 rc = RegQueryValueExW(hkey, value_name, NULL, &type, data, &data_size);
153 if (rc == ERROR_MORE_DATA)
155 max_data_bytes = data_size;
156 data = realloc(data, max_data_bytes);
158 else break;
161 if (rc == ERROR_SUCCESS)
163 output_string(fmt, path);
164 output_value(value_name, type, data, data_size);
165 output_string(newlineW);
166 num_values_found++;
169 free(data);
171 if (!recurse)
173 if (rc == ERROR_FILE_NOT_FOUND)
175 if (value_name && *value_name)
177 output_message(STRING_VALUE_NONEXIST);
178 return 1;
180 output_string(fmt, path);
181 output_value(NULL, REG_SZ, NULL, 0);
183 return 0;
186 subkey_name = malloc(MAX_SUBKEY_LEN * sizeof(WCHAR));
188 path_len = lstrlenW(path);
190 i = 0;
191 for (;;)
193 subkey_len = MAX_SUBKEY_LEN;
194 rc = RegEnumKeyExW(hkey, i, subkey_name, &subkey_len, NULL, NULL, NULL, NULL);
195 if (rc == ERROR_SUCCESS)
197 subkey_path = build_subkey_path(path, path_len, subkey_name, subkey_len);
198 if (!RegOpenKeyExW(hkey, subkey_name, 0, KEY_READ, &subkey))
200 query_value(subkey, value_name, subkey_path, recurse);
201 RegCloseKey(subkey);
203 free(subkey_path);
204 i++;
206 else break;
209 free(subkey_name);
210 return 0;
213 static int query_all(HKEY hkey, WCHAR *path, BOOL recurse, BOOL recursing)
215 LONG rc;
216 DWORD num_values;
217 DWORD max_value_len = 256, value_len;
218 DWORD max_data_bytes = 2048, data_size;
219 DWORD subkey_len;
220 DWORD i, type, path_len;
221 WCHAR *value_name, *subkey_name, *subkey_path;
222 BYTE *data;
223 HKEY subkey;
225 rc = RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL,
226 &num_values, NULL, NULL, NULL, NULL);
227 if (rc) return 1;
229 if (num_values || recursing)
230 output_string(L"%1\n", path);
232 value_name = malloc(max_value_len * sizeof(WCHAR));
233 data = malloc(max_data_bytes);
235 i = 0;
236 for (;;)
238 value_len = max_value_len;
239 data_size = max_data_bytes;
240 rc = RegEnumValueW(hkey, i, value_name, &value_len, NULL, &type, data, &data_size);
241 if (rc == ERROR_SUCCESS)
243 output_value(value_name, type, data, data_size);
244 i++;
246 else if (rc == ERROR_MORE_DATA)
248 if (data_size > max_data_bytes)
250 max_data_bytes = data_size;
251 data = realloc(data, max_data_bytes);
253 else
255 max_value_len *= 2;
256 value_name = realloc(value_name, max_value_len * sizeof(WCHAR));
259 else break;
262 free(data);
263 free(value_name);
265 if (i || recursing)
266 output_string(newlineW);
268 subkey_name = malloc(MAX_SUBKEY_LEN * sizeof(WCHAR));
270 path_len = lstrlenW(path);
272 i = 0;
273 for (;;)
275 subkey_len = MAX_SUBKEY_LEN;
276 rc = RegEnumKeyExW(hkey, i, subkey_name, &subkey_len, NULL, NULL, NULL, NULL);
277 if (rc == ERROR_SUCCESS)
279 if (recurse)
281 subkey_path = build_subkey_path(path, path_len, subkey_name, subkey_len);
282 if (!RegOpenKeyExW(hkey, subkey_name, 0, KEY_READ, &subkey))
284 query_all(subkey, subkey_path, recurse, TRUE);
285 RegCloseKey(subkey);
287 free(subkey_path);
289 else output_string(L"%1\\%2\n", path, subkey_name);
290 i++;
292 else break;
295 free(subkey_name);
296 return 0;
299 static int run_query(HKEY root, WCHAR *path, WCHAR *key_name, WCHAR *value_name,
300 BOOL value_empty, BOOL recurse)
302 HKEY hkey;
303 int ret;
305 if (RegOpenKeyExW(root, path, 0, KEY_READ, &hkey) != ERROR_SUCCESS)
307 output_message(STRING_KEY_NONEXIST);
308 return 1;
311 output_string(newlineW);
313 if (value_name || value_empty)
315 ret = query_value(hkey, value_name, key_name, recurse);
316 if (recurse)
317 output_message(STRING_MATCHES_FOUND, num_values_found);
319 else
320 ret = query_all(hkey, key_name, recurse, FALSE);
322 RegCloseKey(hkey);
324 return ret;
327 int reg_query(int argc, WCHAR *argvW[])
329 HKEY root;
330 WCHAR *path, *key_name, *value_name = NULL;
331 BOOL value_empty = FALSE, recurse = FALSE;
332 int i;
334 if (!parse_registry_key(argvW[2], &root, &path))
335 return 1;
337 for (i = 3; i < argc; i++)
339 WCHAR *str;
341 if (argvW[i][0] != '/' && argvW[i][0] != '-')
342 goto invalid;
344 str = &argvW[i][1];
346 if (!lstrcmpiW(str, L"ve"))
348 if (value_empty) goto invalid;
349 value_empty = TRUE;
350 continue;
352 else if (!lstrcmpiW(str, L"reg:32") || !lstrcmpiW(str, L"reg:64"))
353 continue;
354 else if (!str[0] || str[1])
355 goto invalid;
357 switch (towlower(*str))
359 case 'v':
360 if (value_name || !(value_name = argvW[++i]))
361 goto invalid;
362 break;
363 case 's':
364 if (recurse) goto invalid;
365 recurse = TRUE;
366 break;
367 default:
368 goto invalid;
372 if (value_name && value_empty)
373 goto invalid;
375 key_name = get_long_key(root, path);
377 return run_query(root, path, key_name, value_name, value_empty, recurse);
379 invalid:
380 output_message(STRING_INVALID_SYNTAX);
381 output_message(STRING_FUNC_HELP, wcsupr(argvW[1]));
382 return 1;