2 * Copyright 2008 Andrew Riedi
3 * Copyright 2016-2017, 2021 Hugh McMaster
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include <wine/debug.h>
23 WINE_DEFAULT_DEBUG_CHANNEL(reg
);
28 const WCHAR
*short_name
;
29 const WCHAR
*long_name
;
33 {HKEY_LOCAL_MACHINE
, L
"HKLM", L
"HKEY_LOCAL_MACHINE"},
34 {HKEY_CURRENT_USER
, L
"HKCU", L
"HKEY_CURRENT_USER"},
35 {HKEY_CLASSES_ROOT
, L
"HKCR", L
"HKEY_CLASSES_ROOT"},
36 {HKEY_USERS
, L
"HKU", L
"HKEY_USERS"},
37 {HKEY_CURRENT_CONFIG
, L
"HKCC", L
"HKEY_CURRENT_CONFIG"},
40 const struct reg_type_rels type_rels
[] =
42 {REG_NONE
, L
"REG_NONE"},
44 {REG_EXPAND_SZ
, L
"REG_EXPAND_SZ"},
45 {REG_BINARY
, L
"REG_BINARY"},
46 {REG_DWORD
, L
"REG_DWORD"},
47 {REG_DWORD_LITTLE_ENDIAN
, L
"REG_DWORD_LITTLE_ENDIAN"},
48 {REG_DWORD_BIG_ENDIAN
, L
"REG_DWORD_BIG_ENDIAN"},
49 {REG_MULTI_SZ
, L
"REG_MULTI_SZ"},
52 void output_writeconsole(const WCHAR
*str
, DWORD wlen
)
56 ret
= WriteConsoleW(GetStdHandle(STD_OUTPUT_HANDLE
), str
, wlen
, &count
, NULL
);
62 /* On Windows WriteConsoleW() fails if the output is redirected. So fall
63 * back to WriteFile(), assuming the console encoding is still the right
66 len
= WideCharToMultiByte(GetConsoleOutputCP(), 0, str
, wlen
, NULL
, 0, NULL
, NULL
);
69 WideCharToMultiByte(GetConsoleOutputCP(), 0, str
, wlen
, msgA
, len
, NULL
, NULL
);
70 WriteFile(GetStdHandle(STD_OUTPUT_HANDLE
), msgA
, len
, &count
, FALSE
);
75 static void output_formatstring(const WCHAR
*fmt
, __ms_va_list va_args
)
80 len
= FormatMessageW(FORMAT_MESSAGE_FROM_STRING
|FORMAT_MESSAGE_ALLOCATE_BUFFER
,
81 fmt
, 0, 0, (WCHAR
*)&str
, 0, &va_args
);
82 if (len
== 0 && GetLastError() != ERROR_NO_WORK_DONE
)
84 WINE_FIXME("Could not format string: le=%u, fmt=%s\n", GetLastError(), wine_dbgstr_w(fmt
));
87 output_writeconsole(str
, len
);
91 void WINAPIV
output_message(unsigned int id
, ...)
97 if (!(len
= LoadStringW(GetModuleHandleW(NULL
), id
, (WCHAR
*)&fmt
, 0)))
99 WINE_FIXME("LoadString failed with %d\n", GetLastError());
104 fmt
= malloc(len
* sizeof(WCHAR
));
107 LoadStringW(GetModuleHandleW(NULL
), id
, fmt
, len
);
109 __ms_va_start(va_args
, id
);
110 output_formatstring(fmt
, va_args
);
111 __ms_va_end(va_args
);
116 void WINAPIV
output_string(const WCHAR
*fmt
, ...)
118 __ms_va_list va_args
;
120 __ms_va_start(va_args
, fmt
);
121 output_formatstring(fmt
, va_args
);
122 __ms_va_end(va_args
);
125 /* ask_confirm() adapted from programs/cmd/builtins.c */
126 BOOL
ask_confirm(unsigned int msgid
, WCHAR
*reg_info
)
132 WCHAR answer
[MAX_PATH
];
136 hmod
= GetModuleHandleW(NULL
);
137 LoadStringW(hmod
, STRING_YES
, Ybuffer
, ARRAY_SIZE(Ybuffer
));
138 LoadStringW(hmod
, STRING_NO
, Nbuffer
, ARRAY_SIZE(Nbuffer
));
139 LoadStringW(hmod
, STRING_DEFAULT_VALUE
, defval
, ARRAY_SIZE(defval
));
141 str
= (reg_info
&& *reg_info
) ? reg_info
: defval
;
145 output_message(msgid
, str
);
146 output_message(STRING_YESNO
);
147 ReadConsoleW(GetStdHandle(STD_INPUT_HANDLE
), answer
, ARRAY_SIZE(answer
), &count
, NULL
);
148 answer
[0] = towupper(answer
[0]);
149 if (answer
[0] == Ybuffer
[0])
151 if (answer
[0] == Nbuffer
[0])
156 static inline BOOL
path_rootname_cmp(const WCHAR
*input_path
, const WCHAR
*rootkey_name
)
158 DWORD length
= lstrlenW(rootkey_name
);
160 return (!wcsnicmp(input_path
, rootkey_name
, length
) &&
161 (input_path
[length
] == 0 || input_path
[length
] == '\\'));
164 HKEY
path_get_rootkey(const WCHAR
*path
)
168 for (i
= 0; i
< ARRAY_SIZE(root_rels
); i
++)
170 if (path_rootname_cmp(path
, root_rels
[i
].short_name
) ||
171 path_rootname_cmp(path
, root_rels
[i
].long_name
))
172 return root_rels
[i
].key
;
178 static BOOL
sane_path(const WCHAR
*key
)
180 unsigned int i
= lstrlenW(key
);
182 if (i
< 3 || (key
[i
- 1] == '\\' && key
[i
- 2] == '\\'))
184 output_message(STRING_INVALID_KEY
);
188 if (key
[0] == '\\' && key
[1] == '\\' && key
[2] != '\\')
190 output_message(STRING_NO_REMOTE
);
197 WCHAR
*build_subkey_path(WCHAR
*path
, DWORD path_len
, WCHAR
*subkey_name
, DWORD subkey_len
)
201 subkey_path
= malloc((path_len
+ subkey_len
+ 2) * sizeof(WCHAR
));
202 swprintf(subkey_path
, path_len
+ subkey_len
+ 2, L
"%s\\%s", path
, subkey_name
);
207 WCHAR
*get_long_key(HKEY root
, WCHAR
*path
)
212 for (i
= 0; i
< ARRAY_SIZE(root_rels
); i
++)
214 if (root
== root_rels
[i
].key
)
218 len
= lstrlenW(root_rels
[i
].long_name
);
222 long_key
= malloc((len
+ 1) * sizeof(WCHAR
));
223 lstrcpyW(long_key
, root_rels
[i
].long_name
);
227 len
+= lstrlenW(path
) + 1; /* add one for the concatenating backslash */
228 long_key
= malloc((len
+ 1) * sizeof(WCHAR
));
229 swprintf(long_key
, len
+ 1, L
"%s\\%s", root_rels
[i
].long_name
, path
);
233 BOOL
parse_registry_key(const WCHAR
*key
, HKEY
*root
, WCHAR
**path
)
240 *root
= path_get_rootkey(key
);
243 output_message(STRING_INVALID_SYSTEM_KEY
);
247 *path
= wcschr(key
, '\\');
256 output_message(STRING_INVALID_SYSTEM_KEY
);
260 p
= *path
+ lstrlenW(*path
) - 1;
261 if (*p
== '\\') *p
= 0;
266 BOOL
is_char(const WCHAR s
, const WCHAR c
)
268 return (s
== c
|| s
== towupper(c
));
271 BOOL
is_switch(const WCHAR
*s
, const WCHAR c
)
276 return ((s
[0] == '/' || s
[0] == '-') && is_char(s
[1], c
));
279 static BOOL
is_help_switch(const WCHAR
*s
)
281 return (is_switch(s
, '?') || is_switch(s
, 'h'));
294 static enum operations
get_operation(const WCHAR
*str
, int *op_help
)
296 struct op_info
{ const WCHAR
*op
; int id
; int help_id
; };
298 static const struct op_info op_array
[] =
300 { L
"add", REG_ADD
, STRING_ADD_USAGE
},
301 { L
"copy", REG_COPY
, STRING_COPY_USAGE
},
302 { L
"delete", REG_DELETE
, STRING_DELETE_USAGE
},
303 { L
"export", REG_EXPORT
, STRING_EXPORT_USAGE
},
304 { L
"import", REG_IMPORT
, STRING_IMPORT_USAGE
},
305 { L
"query", REG_QUERY
, STRING_QUERY_USAGE
},
309 const struct op_info
*ptr
;
311 for (ptr
= op_array
; ptr
->op
; ptr
++)
313 if (!lstrcmpiW(str
, ptr
->op
))
315 *op_help
= ptr
->help_id
;
323 int __cdecl
wmain(int argc
, WCHAR
*argvW
[])
329 output_message(STRING_INVALID_SYNTAX
);
330 output_message(STRING_REG_HELP
);
334 if (is_help_switch(argvW
[1]))
336 output_message(STRING_USAGE
);
340 op
= get_operation(argvW
[1], &op_help
);
342 if (op
== REG_INVALID
)
344 output_message(STRING_INVALID_OPTION
, argvW
[1]);
345 output_message(STRING_REG_HELP
);
348 else if (argc
== 2) /* Valid operation, no arguments supplied */
351 if (is_help_switch(argvW
[2]))
353 if (argc
> 3) goto invalid
;
355 output_message(op_help
);
356 output_message(STRING_REG_VIEW_USAGE
);
361 return reg_add(argc
, argvW
);
364 return reg_copy(argc
, argvW
);
366 if (op
== REG_DELETE
)
367 return reg_delete(argc
, argvW
);
369 if (op
== REG_EXPORT
)
370 return reg_export(argc
, argvW
);
372 if (op
== REG_IMPORT
)
373 return reg_import(argc
, argvW
);
375 return reg_query(argc
, argvW
);
378 output_message(STRING_INVALID_SYNTAX
);
379 output_message(STRING_FUNC_HELP
, wcsupr(argvW
[1]));