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