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
));
54 for (i
= 0; i
< size_bytes
; i
++)
55 ptr
+= swprintf(ptr
, 3, L
"%02X", src
[i
]);
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
);
70 const int two_wchars
= 2 * sizeof(WCHAR
);
72 const WCHAR
*tmp
= (const WCHAR
*)src
;
75 if (size_bytes
<= two_wchars
)
77 buffer
= malloc(sizeof(WCHAR
));
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
++)
89 buffer
[destindex
] = tmp
[i
];
92 buffer
[destindex
++] = '\\';
93 buffer
[destindex
] = '0';
96 buffer
[destindex
] = 0;
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";
111 if (value_name
&& value_name
[0])
112 output_string(fmt
, value_name
);
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
));
122 reg_data
= reg_data_to_wchar(type
, data
, data_size
);
123 output_string(fmt
, reg_data
);
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
)
139 DWORD max_data_bytes
= 2048, data_size
;
141 DWORD type
, path_len
, i
;
143 static const WCHAR
*fmt
= L
"%1\n";
144 WCHAR
*subkey_name
, *subkey_path
;
147 data
= malloc(max_data_bytes
);
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
);
161 if (rc
== ERROR_SUCCESS
)
163 output_string(fmt
, path
);
164 output_value(value_name
, type
, data
, data_size
);
165 output_string(newlineW
);
173 if (rc
== ERROR_FILE_NOT_FOUND
)
175 if (value_name
&& *value_name
)
177 output_message(STRING_VALUE_NONEXIST
);
180 output_string(fmt
, path
);
181 output_value(NULL
, REG_SZ
, NULL
, 0);
186 subkey_name
= malloc(MAX_SUBKEY_LEN
* sizeof(WCHAR
));
188 path_len
= lstrlenW(path
);
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
);
213 static int query_all(HKEY hkey
, WCHAR
*path
, BOOL recurse
, BOOL recursing
)
217 DWORD max_value_len
= 256, value_len
;
218 DWORD max_data_bytes
= 2048, data_size
;
220 DWORD i
, type
, path_len
;
221 WCHAR
*value_name
, *subkey_name
, *subkey_path
;
225 rc
= RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
226 &num_values
, NULL
, NULL
, NULL
, NULL
);
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
);
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
);
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
);
256 value_name
= realloc(value_name
, max_value_len
* sizeof(WCHAR
));
266 output_string(newlineW
);
268 subkey_name
= malloc(MAX_SUBKEY_LEN
* sizeof(WCHAR
));
270 path_len
= lstrlenW(path
);
275 subkey_len
= MAX_SUBKEY_LEN
;
276 rc
= RegEnumKeyExW(hkey
, i
, subkey_name
, &subkey_len
, NULL
, NULL
, NULL
, NULL
);
277 if (rc
== ERROR_SUCCESS
)
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
);
289 else output_string(L
"%1\\%2\n", path
, subkey_name
);
299 static int run_query(HKEY root
, WCHAR
*path
, WCHAR
*key_name
, WCHAR
*value_name
,
300 BOOL value_empty
, BOOL recurse
)
305 if (RegOpenKeyExW(root
, path
, 0, KEY_READ
, &hkey
) != ERROR_SUCCESS
)
307 output_message(STRING_KEY_NONEXIST
);
311 output_string(newlineW
);
313 if (value_name
|| value_empty
)
315 ret
= query_value(hkey
, value_name
, key_name
, recurse
);
317 output_message(STRING_MATCHES_FOUND
, num_values_found
);
320 ret
= query_all(hkey
, key_name
, recurse
, FALSE
);
327 int reg_query(int argc
, WCHAR
*argvW
[])
330 WCHAR
*path
, *key_name
, *value_name
= NULL
;
331 BOOL value_empty
= FALSE
, recurse
= FALSE
;
334 if (!parse_registry_key(argvW
[2], &root
, &path
))
337 for (i
= 3; i
< argc
; i
++)
341 if (argvW
[i
][0] != '/' && argvW
[i
][0] != '-')
346 if (!lstrcmpiW(str
, L
"ve"))
348 if (value_empty
) goto invalid
;
352 else if (!lstrcmpiW(str
, L
"reg:32") || !lstrcmpiW(str
, L
"reg:64"))
354 else if (!str
[0] || str
[1])
357 switch (towlower(*str
))
360 if (value_name
|| !(value_name
= argvW
[++i
]))
364 if (recurse
) goto invalid
;
372 if (value_name
&& value_empty
)
375 key_name
= get_long_key(root
, path
);
377 return run_query(root
, path
, key_name
, value_name
, value_empty
, recurse
);
380 output_message(STRING_INVALID_SYNTAX
);
381 output_message(STRING_FUNC_HELP
, wcsupr(argvW
[1]));