ntdll: Fix some spec file entries.
[wine.git] / programs / regedit / regedit.c
blob47fec6334a4aef287017b21490c15b2ee2d2cade
1 /*
2 * Windows regedit.exe registry editor implementation.
4 * Copyright 2002 Andriy Palamarchuk
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <windows.h>
24 #include <shellapi.h>
25 #include "wine/unicode.h"
26 #include "wine/debug.h"
27 #include "regproc.h"
29 WINE_DEFAULT_DEBUG_CHANNEL(regedit);
31 static void output_writeconsole(const WCHAR *str, DWORD wlen)
33 DWORD count, ret;
35 ret = WriteConsoleW(GetStdHandle(STD_OUTPUT_HANDLE), str, wlen, &count, NULL);
36 if (!ret)
38 DWORD len;
39 char *msgA;
41 /* WriteConsole() fails on Windows if its output is redirected. If this occurs,
42 * we should call WriteFile() and assume the console encoding is still correct.
44 len = WideCharToMultiByte(GetConsoleOutputCP(), 0, str, wlen, NULL, 0, NULL, NULL);
45 msgA = HeapAlloc(GetProcessHeap(), 0, len);
46 if (!msgA) return;
48 WideCharToMultiByte(GetConsoleOutputCP(), 0, str, wlen, msgA, len, NULL, NULL);
49 WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), msgA, len, &count, FALSE);
50 HeapFree(GetProcessHeap(), 0, msgA);
54 static void output_formatstring(const WCHAR *fmt, __ms_va_list va_args)
56 WCHAR *str;
57 DWORD len;
59 SetLastError(NO_ERROR);
60 len = FormatMessageW(FORMAT_MESSAGE_FROM_STRING|FORMAT_MESSAGE_ALLOCATE_BUFFER,
61 fmt, 0, 0, (WCHAR *)&str, 0, &va_args);
62 if (len == 0 && GetLastError() != NO_ERROR)
64 WINE_FIXME("Could not format string: le=%u, fmt=%s\n", GetLastError(), wine_dbgstr_w(fmt));
65 return;
67 output_writeconsole(str, len);
68 LocalFree(str);
71 void __cdecl output_message(unsigned int id, ...)
73 WCHAR fmt[1536];
74 __ms_va_list va_args;
76 if (!LoadStringW(GetModuleHandleW(NULL), id, fmt, sizeof(fmt)/sizeof(*fmt)))
78 WINE_FIXME("LoadString failed with %d\n", GetLastError());
79 return;
81 __ms_va_start(va_args, id);
82 output_formatstring(fmt, va_args);
83 __ms_va_end(va_args);
86 typedef enum {
87 ACTION_ADD, ACTION_EXPORT, ACTION_DELETE
88 } REGEDIT_ACTION;
90 static void PerformRegAction(REGEDIT_ACTION action, WCHAR **argv, int *i)
92 switch (action) {
93 case ACTION_ADD: {
94 WCHAR *filename = argv[*i];
95 WCHAR hyphen[] = {'-',0};
96 WCHAR *realname = NULL;
97 FILE *reg_file;
99 if (!strcmpW(filename, hyphen))
100 reg_file = stdin;
101 else
103 int size;
104 WCHAR rb_mode[] = {'r','b',0};
106 size = SearchPathW(NULL, filename, NULL, 0, NULL, NULL);
107 if (size > 0)
109 realname = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR));
110 size = SearchPathW(NULL, filename, NULL, size, realname, NULL);
112 if (size == 0)
114 output_message(STRING_FILE_NOT_FOUND, filename);
115 HeapFree(GetProcessHeap(), 0, realname);
116 return;
118 reg_file = _wfopen(realname, rb_mode);
119 if (reg_file == NULL)
121 WCHAR regedit[] = {'r','e','g','e','d','i','t',0};
122 _wperror(regedit);
123 output_message(STRING_CANNOT_OPEN_FILE, filename);
124 HeapFree(GetProcessHeap(), 0, realname);
125 return;
128 import_registry_file(reg_file);
129 if (realname)
131 HeapFree(GetProcessHeap(), 0, realname);
132 fclose(reg_file);
134 break;
136 case ACTION_DELETE:
137 delete_registry_key(argv[*i]);
138 break;
139 case ACTION_EXPORT: {
140 WCHAR *filename = argv[*i];
141 WCHAR *key_name = argv[++(*i)];
143 if (key_name && *key_name)
144 export_registry_key(filename, key_name, REG_FORMAT_4);
145 else
146 export_registry_key(filename, NULL, REG_FORMAT_4);
147 break;
149 default:
150 output_message(STRING_UNHANDLED_ACTION);
151 exit(1);
152 break;
156 BOOL ProcessCmdLine(WCHAR *cmdline)
158 WCHAR **argv;
159 int argc, i;
160 REGEDIT_ACTION action = ACTION_ADD;
162 argv = CommandLineToArgvW(cmdline, &argc);
164 if (!argv)
165 return FALSE;
167 if (argc == 1)
169 LocalFree(argv);
170 return FALSE;
173 for (i = 1; i < argc; i++)
175 if (argv[i][0] != '/' && argv[i][0] != '-')
176 break; /* No flags specified. */
178 if (!argv[i][1] && argv[i][0] == '-')
179 break; /* '-' is a filename. It indicates we should use stdin. */
181 if (argv[i][1] && argv[i][2] && argv[i][2] != ':')
182 break; /* This is a file path beginning with '/'. */
184 switch (toupperW(argv[i][1]))
186 case '?':
187 output_message(STRING_USAGE);
188 exit(0);
189 break;
190 case 'D':
191 action = ACTION_DELETE;
192 break;
193 case 'E':
194 action = ACTION_EXPORT;
195 break;
196 case 'C':
197 case 'L':
198 case 'R':
199 /* unhandled */;
200 break;
201 case 'S':
202 case 'V':
203 /* ignored */;
204 break;
205 default:
206 output_message(STRING_INVALID_SWITCH, argv[i]);
207 output_message(STRING_HELP);
208 exit(1);
212 if (i == argc)
214 switch (action)
216 case ACTION_ADD:
217 case ACTION_EXPORT:
218 output_message(STRING_NO_FILENAME);
219 break;
220 case ACTION_DELETE:
221 output_message(STRING_NO_REG_KEY);
222 break;
224 output_message(STRING_HELP);
225 exit(1);
228 for (; i < argc; i++)
229 PerformRegAction(action, argv, &i);
231 LocalFree(argv);
233 return TRUE;