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
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
;
35 static WCHAR
*reg_data_to_wchar(DWORD type
, const BYTE
*src
, DWORD size_bytes
)
44 buffer
= malloc(size_bytes
);
45 lstrcpyW(buffer
, (WCHAR
*)src
);
52 buffer
= malloc((size_bytes
* 2 + 1) * sizeof(WCHAR
));
62 for (i
= 0; i
< size_bytes
; i
++)
63 ptr
+= swprintf(ptr
, 3, L
"%02X", src
[i
]);
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
);
78 const int two_wchars
= 2 * sizeof(WCHAR
);
80 const WCHAR
*tmp
= (const WCHAR
*)src
;
83 if (size_bytes
<= two_wchars
)
85 buffer
= malloc(sizeof(WCHAR
));
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
++)
97 buffer
[destindex
] = tmp
[i
];
100 buffer
[destindex
++] = '\\';
101 buffer
[destindex
] = '0';
104 buffer
[destindex
] = 0;
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";
119 if (value_name
&& value_name
[0])
120 output_string(fmt
, value_name
);
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
));
130 reg_data
= reg_data_to_wchar(type
, data
, data_size
);
131 output_string(fmt
, reg_data
);
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
)
148 DWORD max_data_bytes
= 2048, data_size
;
150 DWORD type
, path_len
, i
;
152 static const WCHAR
*fmt
= L
"%1\n";
153 WCHAR
*subkey_name
, *subkey_path
;
156 data
= malloc(max_data_bytes
);
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
);
170 if (rc
== ERROR_SUCCESS
)
172 output_string(fmt
, path
);
173 output_value(value_name
, type
, data
, data_size
);
174 output_string(newlineW
);
182 if (rc
== ERROR_FILE_NOT_FOUND
)
184 if (value_name
&& *value_name
)
186 output_message(STRING_VALUE_NONEXIST
);
189 output_string(fmt
, path
);
190 output_value(NULL
, REG_SZ
, NULL
, 0);
195 subkey_name
= malloc(MAX_SUBKEY_LEN
* sizeof(WCHAR
));
197 path_len
= lstrlenW(path
);
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
);
222 static int query_all(HKEY hkey
, WCHAR
*path
, BOOL recurse
, BOOL recursing
)
225 DWORD num_subkeys
, num_values
;
226 DWORD max_value_len
= 256, value_len
;
227 DWORD max_data_bytes
= 2048, data_size
;
229 DWORD i
, type
, path_len
;
230 WCHAR
*value_name
, *subkey_name
, *subkey_path
;
234 rc
= RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, &num_subkeys
, NULL
,
235 NULL
, &num_values
, NULL
, NULL
, NULL
, NULL
);
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
);
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
);
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
);
265 value_name
= realloc(value_name
, max_value_len
* sizeof(WCHAR
));
275 output_string(newlineW
);
280 subkey_name
= malloc(MAX_SUBKEY_LEN
* sizeof(WCHAR
));
282 path_len
= lstrlenW(path
);
287 subkey_len
= MAX_SUBKEY_LEN
;
288 rc
= RegEnumKeyExW(hkey
, i
, subkey_name
, &subkey_len
, NULL
, NULL
, NULL
, NULL
);
289 if (rc
== ERROR_SUCCESS
)
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
);
301 else output_string(L
"%1\\%2\n", path
, subkey_name
);
311 static int run_query(HKEY root
, WCHAR
*path
, WCHAR
*key_name
, WCHAR
*value_name
,
312 BOOL value_empty
, BOOL recurse
)
317 if (RegOpenKeyExW(root
, path
, 0, KEY_READ
|sam
, &hkey
))
319 output_message(STRING_KEY_NONEXIST
);
323 output_string(newlineW
);
325 if (value_name
|| value_empty
)
327 ret
= query_value(hkey
, value_name
, key_name
, recurse
);
329 output_message(STRING_MATCHES_FOUND
, num_values_found
);
332 ret
= query_all(hkey
, key_name
, recurse
, FALSE
);
339 int reg_query(int argc
, WCHAR
*argvW
[])
342 WCHAR
*path
, *key_name
, *value_name
= NULL
;
343 BOOL value_empty
= FALSE
, recurse
= FALSE
;
346 if (!parse_registry_key(argvW
[2], &root
, &path
))
349 for (i
= 3; i
< argc
; i
++)
353 if (argvW
[i
][0] != '/' && argvW
[i
][0] != '-')
358 if (!lstrcmpiW(str
, L
"ve"))
360 if (value_empty
) goto invalid
;
364 else if (!lstrcmpiW(str
, L
"reg:32"))
366 if (sam
& KEY_WOW64_32KEY
) goto invalid
;
367 sam
|= KEY_WOW64_32KEY
;
370 else if (!lstrcmpiW(str
, L
"reg:64"))
372 if (sam
& KEY_WOW64_64KEY
) goto invalid
;
373 sam
|= KEY_WOW64_64KEY
;
376 else if (!str
[0] || str
[1])
379 switch (towlower(*str
))
382 if (value_name
|| !(value_name
= argvW
[++i
]))
386 if (recurse
) goto invalid
;
394 if (value_name
&& value_empty
)
397 if (sam
== (KEY_WOW64_32KEY
|KEY_WOW64_64KEY
))
400 key_name
= get_long_key(root
, path
);
402 return run_query(root
, path
, key_name
, value_name
, value_empty
, recurse
);
405 output_message(STRING_INVALID_SYNTAX
);
406 output_message(STRING_FUNC_HELP
, wcsupr(argvW
[1]));