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 static const LPCWSTR usage = 24 L"Usage:\n" 25 L" regedit filenames\n" 26 L" regedit /E filename [regpath]\n" 27 L" regedit /D regpath\n" 28 L"\n" 29 L"filenames - List of registry files names\n" 30 L"filename - Registry file name\n" 31 L"regpath - Name of the registry key\n" 32 L"\n" 33 L"When is called without any switches adds contents of the specified\n" 34 L"registry files to the registry.\n" 35 L"\n" 36 L"Switches:\n" 37 L" /E - Exports contents of the specified registry key to the specified\n" 38 L" file. Exports the whole registry if no key is specified.\n" 39 L" /D - Deletes specified registry key\n" 40 L" /S - Silent execution, can be used with any other switch.\n" 41 L" The only existing mode, exists for compatibility with Windows regedit.\n" 42 L" /V - Advanced mode, can be used with any other switch.\n" 43 L" Ignored, exists for compatibility with Windows regedit.\n" 44 L" /L - Location of system.dat file. Can be used with any other switch.\n" 45 L" Ignored. Exists for compatibility with Windows regedit.\n" 46 L" /R - Location of user.dat file. Can be used with any other switch.\n" 47 L" Ignored. Exists for compatibility with Windows regedit.\n" 48 L" /? - Print this help. Any other switches are ignored.\n" 49 L" /C - Create registry from. Not implemented.\n" 50 L"\n" 51 L"The switches are case-insensitive, can be prefixed either by '-' or '/'.\n" 52 L"This program is command-line compatible with Microsoft Windows\n" 53 L"regedit.\n"; 54 55 typedef enum 56 { 57 ACTION_UNDEF, ACTION_ADD, ACTION_EXPORT, ACTION_DELETE 58 } REGEDIT_ACTION; 59 60 61 LPCWSTR getAppName(void) 62 { 63 return L"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 size_t 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 fwprintf(stderr, L"%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 switch (action) 138 { 139 case ACTION_ADD: 140 { 141 WCHAR szText[512]; 142 WCHAR filename[MAX_PATH]; 143 FILE *fp; 144 145 get_file_name(&s, filename); 146 if (!filename[0]) 147 { 148 InfoMessageBox(NULL, MB_OK | MB_ICONINFORMATION, NULL, L"No file name is specified."); 149 InfoMessageBox(NULL, MB_OK | MB_ICONINFORMATION, szTitle, usage); 150 exit(4); 151 } 152 153 while (filename[0]) 154 { 155 /* Request import confirmation */ 156 if (!silent) 157 { 158 int choice; 159 160 LoadStringW(hInst, IDS_IMPORT_PROMPT, szText, COUNT_OF(szText)); 161 162 choice = InfoMessageBox(NULL, MB_YESNOCANCEL | MB_ICONWARNING, szTitle, szText, filename); 163 164 switch (choice) 165 { 166 case IDNO: 167 goto cont; 168 case IDCANCEL: 169 /* The cancel case is useful if the user is importing more than one registry file 170 at a time, and wants to back out anytime during the import process. This way, the 171 user doesn't have to resort to ending the regedit process abruptly just to cancel 172 the operation. */ 173 return TRUE; 174 default: 175 break; 176 } 177 } 178 179 /* Open the file */ 180 fp = _wfopen(filename, L"r"); 181 182 /* Import it */ 183 if (fp == NULL || !import_registry_file(fp)) 184 { 185 /* Error opening the file */ 186 if (!silent) 187 { 188 LoadStringW(hInst, IDS_IMPORT_ERROR, szText, COUNT_OF(szText)); 189 InfoMessageBox(NULL, MB_OK | MB_ICONERROR, szTitle, szText, filename); 190 } 191 } 192 else 193 { 194 /* Show successful import */ 195 if (!silent) 196 { 197 LoadStringW(hInst, IDS_IMPORT_OK, szText, COUNT_OF(szText)); 198 InfoMessageBox(NULL, MB_OK | MB_ICONINFORMATION, szTitle, szText, filename); 199 } 200 } 201 202 /* Close the file */ 203 if (fp) fclose(fp); 204 205 cont: 206 get_file_name(&s, filename); 207 } 208 break; 209 } 210 211 case ACTION_DELETE: 212 { 213 WCHAR reg_key_name[KEY_MAX_LEN]; 214 get_file_name(&s, reg_key_name); 215 if (!reg_key_name[0]) 216 { 217 InfoMessageBox(NULL, MB_OK | MB_ICONINFORMATION, NULL, L"No registry key is specified for removal."); 218 InfoMessageBox(NULL, MB_OK | MB_ICONINFORMATION, szTitle, usage); 219 exit(6); 220 } 221 delete_registry_key(reg_key_name); 222 break; 223 } 224 225 case ACTION_EXPORT: 226 { 227 WCHAR filename[MAX_PATH]; 228 229 filename[0] = L'\0'; 230 get_file_name(&s, filename); 231 if (!filename[0]) 232 { 233 InfoMessageBox(NULL, MB_OK | MB_ICONINFORMATION, NULL, L"No file name is specified."); 234 InfoMessageBox(NULL, MB_OK | MB_ICONINFORMATION, szTitle, usage); 235 exit(7); 236 } 237 238 if (s[0]) 239 { 240 WCHAR reg_key_name[KEY_MAX_LEN]; 241 get_file_name(&s, reg_key_name); 242 export_registry_key(filename, reg_key_name, REG_FORMAT_4); 243 } 244 else 245 { 246 export_registry_key(filename, NULL, REG_FORMAT_4); 247 } 248 break; 249 } 250 251 default: 252 fwprintf(stderr, L"%s: Unhandled action!\n", getAppName()); 253 exit(8); 254 break; 255 } 256 257 return TRUE; 258 } 259 260 /** 261 * Process unknown switch. 262 * 263 * Params: 264 * chu - the switch character in upper-case. 265 * s - the command line string where s points to the switch character. 266 */ 267 static void error_unknown_switch(WCHAR chu, LPWSTR s) 268 { 269 if (iswalpha(chu)) 270 { 271 fwprintf(stderr, L"%s: Undefined switch /%c!\n", getAppName(), chu); 272 } 273 else 274 { 275 fwprintf(stderr, L"%s: Alphabetic character is expected after '%c' " 276 L"in switch specification\n", getAppName(), *(s - 1)); 277 } 278 exit(1); 279 } 280 281 BOOL ProcessCmdLine(LPWSTR lpCmdLine) 282 { 283 BOOL silent = FALSE; 284 REGEDIT_ACTION action = ACTION_UNDEF; 285 LPWSTR s = lpCmdLine; /* command line pointer */ 286 WCHAR ch = *s; /* current character */ 287 288 while (ch && ((ch == L'-') || (ch == L'/'))) 289 { 290 WCHAR chu; 291 WCHAR ch2; 292 293 s++; 294 ch = *s; 295 ch2 = *(s + 1); 296 chu = towupper(ch); 297 if (!ch2 || iswspace(ch2)) 298 { 299 if (chu == L'S') 300 { 301 /* Silence dialogs */ 302 silent = TRUE; 303 } 304 else if (chu == L'V') 305 { 306 /* Ignore this switch */ 307 } 308 else 309 { 310 switch (chu) 311 { 312 case L'D': 313 action = ACTION_DELETE; 314 break; 315 case L'E': 316 action = ACTION_EXPORT; 317 break; 318 case L'?': 319 InfoMessageBox(NULL, MB_OK | MB_ICONINFORMATION, szTitle, usage); 320 exit(3); 321 break; 322 default: 323 error_unknown_switch(chu, s); 324 break; 325 } 326 } 327 s++; 328 } 329 else 330 { 331 if (ch2 == L':') 332 { 333 switch (chu) 334 { 335 case L'L': 336 /* fall through */ 337 case L'R': 338 s += 2; 339 while (*s && !iswspace(*s)) 340 { 341 s++; 342 } 343 break; 344 default: 345 error_unknown_switch(chu, s); 346 break; 347 } 348 } 349 else 350 { 351 /* this is a file name, starting from '/' */ 352 s--; 353 break; 354 } 355 } 356 /* skip spaces to the next parameter */ 357 ch = *s; 358 while (ch && iswspace(ch)) 359 { 360 s++; 361 ch = *s; 362 } 363 } 364 365 if (*s && action == ACTION_UNDEF) 366 action = ACTION_ADD; 367 368 if (action != ACTION_UNDEF) 369 return PerformRegAction(action, s, silent); 370 else 371 return FALSE; 372 } 373