66ce69f1005a8913fce827c72428405c8ef5a7a2
[reactos.git] / reactos / base / applications / regedit / regedit.c
1 /*
2 * Windows regedit.exe registry editor implementation.
3 *
4 * Copyright (C) 2002 Andriy Palamarchuk
5 *
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.
10 *
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.
15 *
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 Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21 #include <regedit.h>
22
23
24 static const LPCWSTR usage =
25 L"Usage:\n"
26 L" regedit filenames\n"
27 L" regedit /E filename [regpath]\n"
28 L" regedit /D regpath\n"
29 L"\n"
30 L"filenames - List of registry files names\n"
31 L"filename - Registry file name\n"
32 L"regpath - Name of the registry key\n"
33 L"\n"
34 L"When is called without any switches adds contents of the specified\n"
35 L"registry files to the registry.\n"
36 L"\n"
37 L"Switches:\n"
38 L" /E - Exports contents of the specified registry key to the specified\n"
39 L" file. Exports the whole registry if no key is specified.\n"
40 L" /D - Deletes specified registry key\n"
41 L" /S - Silent execution, can be used with any other switch.\n"
42 L" The only existing mode, exists for compatibility with Windows regedit.\n"
43 L" /V - Advanced mode, can be used with any other switch.\n"
44 L" Ignored, exists for compatibility with Windows regedit.\n"
45 L" /L - Location of system.dat file. Can be used with any other switch.\n"
46 L" Ignored. Exists for compatibility with Windows regedit.\n"
47 L" /R - Location of user.dat file. Can be used with any other switch.\n"
48 L" Ignored. Exists for compatibility with Windows regedit.\n"
49 L" /? - Print this help. Any other switches are ignored.\n"
50 L" /C - Create registry from. Not implemented.\n"
51 L"\n"
52 L"The switches are case-insensitive, can be prefixed either by '-' or '/'.\n"
53 L"This program is command-line compatible with Microsoft Windows\n"
54 L"regedit.\n";
55
56 typedef enum
57 {
58 ACTION_UNDEF, ACTION_ADD, ACTION_EXPORT, ACTION_DELETE
59 } REGEDIT_ACTION;
60
61
62 LPCWSTR getAppName(void)
63 {
64 return L"regedit";
65 }
66
67 /******************************************************************************
68 * Copies file name from command line string to the buffer.
69 * Rewinds the command line string pointer to the next non-space character
70 * after the file name.
71 * Buffer contains an empty string if no filename was found;
72 *
73 * params:
74 * command_line - command line current position pointer
75 * where *s[0] is the first symbol of the file name.
76 * file_name - buffer to write the file name to.
77 */
78 void get_file_name(LPWSTR *command_line, LPWSTR file_name)
79 {
80 WCHAR *s = *command_line;
81 size_t pos = 0; /* position of pointer "s" in *command_line */
82 file_name[0] = 0;
83
84 if (!s[0])
85 {
86 return;
87 }
88
89 if (s[0] == L'"')
90 {
91 s++;
92 (*command_line)++;
93 while(s[0] != L'"')
94 {
95 if (!s[0])
96 {
97 fwprintf(stderr, L"%s: Unexpected end of file name!\n", getAppName());
98 exit(1);
99 }
100 s++;
101 pos++;
102 }
103 }
104 else
105 {
106 while(s[0] && !iswspace(s[0]))
107 {
108 s++;
109 pos++;
110 }
111 }
112 memcpy(file_name, *command_line, pos * sizeof(WCHAR));
113 /* remove the last backslash */
114 if (file_name[pos - 1] == L'\\')
115 {
116 file_name[pos - 1] = L'\0';
117 }
118 else
119 {
120 file_name[pos] = L'\0';
121 }
122
123 if (s[0])
124 {
125 s++;
126 pos++;
127 }
128 while(s[0] && iswspace(s[0]))
129 {
130 s++;
131 pos++;
132 }
133 (*command_line) += pos;
134 }
135
136 BOOL PerformRegAction(REGEDIT_ACTION action, LPWSTR s, BOOL silent)
137 {
138 switch (action)
139 {
140 case ACTION_ADD:
141 {
142 WCHAR szTitle[512], szText[512];
143 WCHAR filename[MAX_PATH];
144 FILE *fp;
145
146 get_file_name(&s, filename);
147 if (!filename[0])
148 {
149 fwprintf(stderr, L"%s: No file name is specified\n", getAppName());
150 // fwprintf(stderr, usage);
151 MessageBoxW(NULL, usage, NULL, MB_OK | MB_ICONINFORMATION);
152 exit(4);
153 }
154
155 LoadStringW(hInst, IDS_APP_TITLE, szTitle, COUNT_OF(szTitle));
156
157 while (filename[0])
158 {
159 /* Request import confirmation */
160 if (!silent)
161 {
162 LoadStringW(hInst, IDS_IMPORT_PROMPT, szText, COUNT_OF(szText));
163
164 if (InfoMessageBox(NULL, MB_YESNO | MB_ICONWARNING, szTitle, szText, filename) != IDYES)
165 goto cont;
166 }
167
168 fp = _wfopen(filename, L"r");
169 if (fp != NULL)
170 {
171 import_registry_file(fp);
172
173 /* Show successful import */
174 if (!silent)
175 {
176 LoadStringW(hInst, IDS_IMPORT_OK, szText, COUNT_OF(szText));
177 InfoMessageBox(NULL, MB_OK | MB_ICONINFORMATION, szTitle, szText, filename);
178 }
179
180 fclose(fp);
181 }
182 else
183 {
184 //LPSTR p = GetMultiByteString(filename);
185 //perror("");
186 fwprintf(stderr, L"%s: Can't open file \"%s\"\n", getAppName(), filename /*p*/);
187 //HeapFree(GetProcessHeap(), 0, p);
188
189 /* Error opening the file */
190 if (!silent)
191 {
192 LoadStringW(hInst, IDS_IMPORT_ERROR, szText, COUNT_OF(szText));
193 InfoMessageBox(NULL, MB_OK | MB_ICONERROR, szTitle, szText, filename);
194 }
195 }
196
197 cont:
198 get_file_name(&s, filename);
199 }
200 break;
201 }
202
203 case ACTION_DELETE:
204 {
205 WCHAR reg_key_name[KEY_MAX_LEN];
206 get_file_name(&s, reg_key_name);
207 if (!reg_key_name[0])
208 {
209 fwprintf(stderr, L"%s: No registry key is specified for removal\n", getAppName());
210 // fwprintf(stderr, usage);
211 MessageBoxW(NULL, usage, NULL, MB_OK | MB_ICONINFORMATION);
212 exit(6);
213 }
214 delete_registry_key(reg_key_name);
215 break;
216 }
217
218 case ACTION_EXPORT:
219 {
220 WCHAR filename[MAX_PATH];
221
222 filename[0] = L'\0';
223 get_file_name(&s, filename);
224 if (!filename[0])
225 {
226 fwprintf(stderr, L"%s: No file name is specified\n", getAppName());
227 // fwprintf(stderr, usage);
228 MessageBoxW(NULL, usage, NULL, MB_OK | MB_ICONINFORMATION);
229 exit(7);
230 }
231
232 if (s[0])
233 {
234 WCHAR reg_key_name[KEY_MAX_LEN];
235 get_file_name(&s, reg_key_name);
236 export_registry_key(filename, reg_key_name, REG_FORMAT_4);
237 }
238 else
239 {
240 export_registry_key(filename, NULL, REG_FORMAT_4);
241 }
242 break;
243 }
244
245 default:
246 fwprintf(stderr, L"%s: Unhandled action!\n", getAppName());
247 exit(8);
248 break;
249 }
250
251 return TRUE;
252 }
253
254 /**
255 * Process unknown switch.
256 *
257 * Params:
258 * chu - the switch character in upper-case.
259 * s - the command line string where s points to the switch character.
260 */
261 static void error_unknown_switch(WCHAR chu, LPWSTR s)
262 {
263 if (iswalpha(chu))
264 {
265 fwprintf(stderr, L"%s: Undefined switch /%c!\n", getAppName(), chu);
266 }
267 else
268 {
269 fwprintf(stderr, L"%s: Alphabetic character is expected after '%c' "
270 L"in switch specification\n", getAppName(), *(s - 1));
271 }
272 exit(1);
273 }
274
275 BOOL ProcessCmdLine(LPWSTR lpCmdLine)
276 {
277 BOOL silent = FALSE;
278 REGEDIT_ACTION action = ACTION_UNDEF;
279 LPWSTR s = lpCmdLine; /* command line pointer */
280 WCHAR ch = *s; /* current character */
281
282 while (ch && ((ch == L'-') || (ch == L'/')))
283 {
284 WCHAR chu;
285 WCHAR ch2;
286
287 s++;
288 ch = *s;
289 ch2 = *(s + 1);
290 chu = towupper(ch);
291 if (!ch2 || iswspace(ch2))
292 {
293 if (chu == L'S')
294 {
295 /* Silence dialogs */
296 silent = TRUE;
297 }
298 else if (chu == L'V')
299 {
300 /* Ignore this switch */
301 }
302 else
303 {
304 switch (chu)
305 {
306 case L'D':
307 action = ACTION_DELETE;
308 break;
309 case L'E':
310 action = ACTION_EXPORT;
311 break;
312 case L'?':
313 //fwprintf(stderr, usage);
314 MessageBoxW(NULL, usage, NULL, MB_OK | MB_ICONINFORMATION);
315 exit(3);
316 break;
317 default:
318 error_unknown_switch(chu, s);
319 break;
320 }
321 }
322 s++;
323 }
324 else
325 {
326 if (ch2 == L':')
327 {
328 switch (chu)
329 {
330 case L'L':
331 /* fall through */
332 case L'R':
333 s += 2;
334 while (*s && !iswspace(*s))
335 {
336 s++;
337 }
338 break;
339 default:
340 error_unknown_switch(chu, s);
341 break;
342 }
343 }
344 else
345 {
346 /* this is a file name, starting from '/' */
347 s--;
348 break;
349 }
350 }
351 /* skip spaces to the next parameter */
352 ch = *s;
353 while (ch && iswspace(ch))
354 {
355 s++;
356 ch = *s;
357 }
358 }
359
360 if (*s && action == ACTION_UNDEF)
361 action = ACTION_ADD;
362
363 if (action != ACTION_UNDEF)
364 return PerformRegAction(action, s, silent);
365 else
366 return FALSE;
367 }