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 InfoMessageBox(NULL, MB_OK | MB_ICONINFORMATION, NULL, L"No file name is specified."); 150 InfoMessageBox(NULL, MB_OK | MB_ICONINFORMATION, NULL, usage); 151 exit(4); 152 } 153 154 LoadStringW(hInst, IDS_APP_TITLE, szTitle, COUNT_OF(szTitle)); 155 156 while (filename[0]) 157 { 158 /* Request import confirmation */ 159 if (!silent) 160 { 161 int choice; 162 163 LoadStringW(hInst, IDS_IMPORT_PROMPT, szText, COUNT_OF(szText)); 164 165 choice = InfoMessageBox(NULL, MB_YESNOCANCEL | MB_ICONWARNING, szTitle, szText, filename); 166 167 switch (choice) 168 { 169 case IDNO: 170 goto cont; 171 case IDCANCEL: 172 /* The cancel case is useful if the user is importing more than one registry file 173 at a time, and wants to back out anytime during the import process. This way, the 174 user doesn't have to resort to ending the regedit process abruptly just to cancel 175 the operation. */ 176 return TRUE; 177 default: 178 break; 179 } 180 } 181 182 /* Open the file */ 183 fp = _wfopen(filename, L"r"); 184 185 /* Import it */ 186 if (fp == NULL || !import_registry_file(fp)) 187 { 188 /* Error opening the file */ 189 if (!silent) 190 { 191 LoadStringW(hInst, IDS_IMPORT_ERROR, szText, COUNT_OF(szText)); 192 InfoMessageBox(NULL, MB_OK | MB_ICONERROR, szTitle, szText, filename); 193 } 194 } 195 else 196 { 197 /* Show successful import */ 198 if (!silent) 199 { 200 LoadStringW(hInst, IDS_IMPORT_OK, szText, COUNT_OF(szText)); 201 InfoMessageBox(NULL, MB_OK | MB_ICONINFORMATION, szTitle, szText, filename); 202 } 203 } 204 205 /* Close the file */ 206 if (fp) fclose(fp); 207 208 cont: 209 get_file_name(&s, filename); 210 } 211 break; 212 } 213 214 case ACTION_DELETE: 215 { 216 WCHAR reg_key_name[KEY_MAX_LEN]; 217 get_file_name(&s, reg_key_name); 218 if (!reg_key_name[0]) 219 { 220 InfoMessageBox(NULL, MB_OK | MB_ICONINFORMATION, NULL, L"No registry key is specified for removal."); 221 InfoMessageBox(NULL, MB_OK | MB_ICONINFORMATION, NULL, usage); 222 exit(6); 223 } 224 delete_registry_key(reg_key_name); 225 break; 226 } 227 228 case ACTION_EXPORT: 229 { 230 WCHAR filename[MAX_PATH]; 231 232 filename[0] = L'\0'; 233 get_file_name(&s, filename); 234 if (!filename[0]) 235 { 236 InfoMessageBox(NULL, MB_OK | MB_ICONINFORMATION, NULL, L"No file name is specified."); 237 InfoMessageBox(NULL, MB_OK | MB_ICONINFORMATION, NULL, usage); 238 exit(7); 239 } 240 241 if (s[0]) 242 { 243 WCHAR reg_key_name[KEY_MAX_LEN]; 244 get_file_name(&s, reg_key_name); 245 export_registry_key(filename, reg_key_name, REG_FORMAT_4); 246 } 247 else 248 { 249 export_registry_key(filename, NULL, REG_FORMAT_4); 250 } 251 break; 252 } 253 254 default: 255 fwprintf(stderr, L"%s: Unhandled action!\n", getAppName()); 256 exit(8); 257 break; 258 } 259 260 return TRUE; 261 } 262 263 /** 264 * Process unknown switch. 265 * 266 * Params: 267 * chu - the switch character in upper-case. 268 * s - the command line string where s points to the switch character. 269 */ 270 static void error_unknown_switch(WCHAR chu, LPWSTR s) 271 { 272 if (iswalpha(chu)) 273 { 274 fwprintf(stderr, L"%s: Undefined switch /%c!\n", getAppName(), chu); 275 } 276 else 277 { 278 fwprintf(stderr, L"%s: Alphabetic character is expected after '%c' " 279 L"in switch specification\n", getAppName(), *(s - 1)); 280 } 281 exit(1); 282 } 283 284 BOOL ProcessCmdLine(LPWSTR lpCmdLine) 285 { 286 BOOL silent = FALSE; 287 REGEDIT_ACTION action = ACTION_UNDEF; 288 LPWSTR s = lpCmdLine; /* command line pointer */ 289 WCHAR ch = *s; /* current character */ 290 291 while (ch && ((ch == L'-') || (ch == L'/'))) 292 { 293 WCHAR chu; 294 WCHAR ch2; 295 296 s++; 297 ch = *s; 298 ch2 = *(s + 1); 299 chu = towupper(ch); 300 if (!ch2 || iswspace(ch2)) 301 { 302 if (chu == L'S') 303 { 304 /* Silence dialogs */ 305 silent = TRUE; 306 } 307 else if (chu == L'V') 308 { 309 /* Ignore this switch */ 310 } 311 else 312 { 313 switch (chu) 314 { 315 case L'D': 316 action = ACTION_DELETE; 317 break; 318 case L'E': 319 action = ACTION_EXPORT; 320 break; 321 case L'?': 322 InfoMessageBox(NULL, MB_OK | MB_ICONINFORMATION, NULL, usage); 323 exit(3); 324 break; 325 default: 326 error_unknown_switch(chu, s); 327 break; 328 } 329 } 330 s++; 331 } 332 else 333 { 334 if (ch2 == L':') 335 { 336 switch (chu) 337 { 338 case L'L': 339 /* fall through */ 340 case L'R': 341 s += 2; 342 while (*s && !iswspace(*s)) 343 { 344 s++; 345 } 346 break; 347 default: 348 error_unknown_switch(chu, s); 349 break; 350 } 351 } 352 else 353 { 354 /* this is a file name, starting from '/' */ 355 s--; 356 break; 357 } 358 } 359 /* skip spaces to the next parameter */ 360 ch = *s; 361 while (ch && iswspace(ch)) 362 { 363 s++; 364 ch = *s; 365 } 366 } 367 368 if (*s && action == ACTION_UNDEF) 369 action = ACTION_ADD; 370 371 if (action != ACTION_UNDEF) 372 return PerformRegAction(action, s, silent); 373 else 374 return FALSE; 375 } 376