/*
* Windows regedit.exe registry editor implementation.
*
- * Copyright 2002 Andriy Palamarchuk
+ * Copyright (C) 2002 Andriy Palamarchuk
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
#include <regedit.h>
-static const char *usage =
- "Usage:\n"
- " regedit filename\n"
- " regedit /E filename [regpath]\n"
- " regedit /D regpath\n"
- "\n"
- "filename - registry file name\n"
- "regpath - name of the registry key\n"
- "\n"
- "When is called without any switches adds contents of the specified\n"
- "registry file to the registry\n"
- "\n"
- "Switches:\n"
- " /E - exports contents of the specified registry key to the specified\n"
- " file. Exports the whole registry if no key is specified.\n"
- " /D - deletes specified registry key\n"
- " /S - silent execution, can be used with any other switch.\n"
- " The only existing mode, exists for compatibility with Windows regedit.\n"
- " /V - advanced mode, can be used with any other switch.\n"
- " Ignored, exists for compatibility with Windows regedit.\n"
- " /L - location of system.dat file. Can be used with any other switch.\n"
- " Ignored. Exists for compatibility with Windows regedit.\n"
- " /R - location of user.dat file. Can be used with any other switch.\n"
- " Ignored. Exists for compatibility with Windows regedit.\n"
- " /? - print this help. Any other switches are ignored.\n"
- " /C - create registry from. Not implemented.\n"
- "\n"
- "The switches are case-insensitive, can be prefixed either by '-' or '/'.\n"
- "This program is command-line compatible with Microsoft Windows\n"
- "regedit.\n";
-
-typedef enum {
+static const LPCWSTR usage =
+ L"Usage:\n"
+ L" regedit filenames\n"
+ L" regedit /E filename [regpath]\n"
+ L" regedit /D regpath\n"
+ L"\n"
+ L"filenames - List of registry files names\n"
+ L"filename - Registry file name\n"
+ L"regpath - Name of the registry key\n"
+ L"\n"
+ L"When is called without any switches adds contents of the specified\n"
+ L"registry files to the registry.\n"
+ L"\n"
+ L"Switches:\n"
+ L" /E - Exports contents of the specified registry key to the specified\n"
+ L" file. Exports the whole registry if no key is specified.\n"
+ L" /D - Deletes specified registry key\n"
+ L" /S - Silent execution, can be used with any other switch.\n"
+ L" The only existing mode, exists for compatibility with Windows regedit.\n"
+ L" /V - Advanced mode, can be used with any other switch.\n"
+ L" Ignored, exists for compatibility with Windows regedit.\n"
+ L" /L - Location of system.dat file. Can be used with any other switch.\n"
+ L" Ignored. Exists for compatibility with Windows regedit.\n"
+ L" /R - Location of user.dat file. Can be used with any other switch.\n"
+ L" Ignored. Exists for compatibility with Windows regedit.\n"
+ L" /? - Print this help. Any other switches are ignored.\n"
+ L" /C - Create registry from. Not implemented.\n"
+ L"\n"
+ L"The switches are case-insensitive, can be prefixed either by '-' or '/'.\n"
+ L"This program is command-line compatible with Microsoft Windows\n"
+ L"regedit.\n";
+
+typedef enum
+{
ACTION_UNDEF, ACTION_ADD, ACTION_EXPORT, ACTION_DELETE
} REGEDIT_ACTION;
-BOOL PerformRegAction(REGEDIT_ACTION action, LPSTR s);
-/**
- * Process unknown switch.
- *
- * Params:
- * chu - the switch character in upper-case.
- * s - the command line string where s points to the switch character.
- */
-static void error_unknown_switch(char chu, char *s)
+LPCWSTR getAppName(void)
{
- if (isalpha(chu)) {
- fprintf(stderr,"%s: Undefined switch /%c!\n", getAppName(), chu);
- } else {
- fprintf(stderr,"%s: Alphabetic character is expected after '%c' "
- "in swit ch specification\n", getAppName(), *(s - 1));
- }
- exit(1);
+ return L"regedit";
}
-BOOL ProcessCmdLine(LPSTR lpCmdLine)
+/******************************************************************************
+ * Copies file name from command line string to the buffer.
+ * Rewinds the command line string pointer to the next non-space character
+ * after the file name.
+ * Buffer contains an empty string if no filename was found;
+ *
+ * params:
+ * command_line - command line current position pointer
+ * where *s[0] is the first symbol of the file name.
+ * file_name - buffer to write the file name to.
+ */
+void get_file_name(LPWSTR *command_line, LPWSTR file_name)
{
- REGEDIT_ACTION action = ACTION_UNDEF;
- LPSTR s = lpCmdLine; /* command line pointer */
- CHAR ch = *s; /* current character */
+ WCHAR *s = *command_line;
+ size_t pos = 0; /* position of pointer "s" in *command_line */
+ file_name[0] = 0;
- setAppName("regedit");
- while (ch && ((ch == '-') || (ch == '/'))) {
- char chu;
- char ch2;
+ if (!s[0])
+ {
+ return;
+ }
+ if (s[0] == L'"')
+ {
s++;
- ch = *s;
- ch2 = *(s+1);
- chu = (CHAR) toupper(ch);
- if (!ch2 || isspace(ch2)) {
- if (chu == 'S' || chu == 'V') {
- /* ignore these switches */
- } else {
- switch (chu) {
- case 'D':
- action = ACTION_DELETE;
- break;
- case 'E':
- action = ACTION_EXPORT;
- break;
- case '?':
- fprintf(stderr,usage);
- exit(0);
- break;
- default:
- error_unknown_switch(chu, s);
- break;
- }
+ (*command_line)++;
+ while(s[0] != L'"')
+ {
+ if (!s[0])
+ {
+ fwprintf(stderr, L"%s: Unexpected end of file name!\n", getAppName());
+ exit(1);
}
s++;
- } else {
- if (ch2 == ':') {
- switch (chu) {
- case 'L':
- /* fall through */
- case 'R':
- s += 2;
- while (*s && !isspace(*s)) {
- s++;
- }
- break;
- default:
- error_unknown_switch(chu, s);
- break;
- }
- } else {
- /* this is a file name, starting from '/' */
- s--;
- break;
- }
+ pos++;
}
- /* skip spaces to the next parameter */
- ch = *s;
- while (ch && isspace(ch)) {
+ }
+ else
+ {
+ while(s[0] && !iswspace(s[0]))
+ {
s++;
- ch = *s;
+ pos++;
}
}
+ memcpy(file_name, *command_line, pos * sizeof(WCHAR));
+ /* remove the last backslash */
+ if (file_name[pos - 1] == L'\\')
+ {
+ file_name[pos - 1] = L'\0';
+ }
+ else
+ {
+ file_name[pos] = L'\0';
+ }
- if (*s && action == ACTION_UNDEF)
- action = ACTION_ADD;
-
- if (action == ACTION_UNDEF)
- return FALSE;
-
- return PerformRegAction(action, s);
+ if (s[0])
+ {
+ s++;
+ pos++;
+ }
+ while(s[0] && iswspace(s[0]))
+ {
+ s++;
+ pos++;
+ }
+ (*command_line) += pos;
}
-BOOL PerformRegAction(REGEDIT_ACTION action, LPSTR s)
+BOOL PerformRegAction(REGEDIT_ACTION action, LPWSTR s, BOOL silent)
{
- switch (action) {
- case ACTION_ADD: {
- CHAR filename[MAX_PATH];
- FILE *reg_file;
+ switch (action)
+ {
+ case ACTION_ADD:
+ {
+ WCHAR szTitle[512], szText[512];
+ WCHAR filename[MAX_PATH];
+ FILE *fp;
get_file_name(&s, filename);
- if (!filename[0]) {
- fprintf(stderr,"%s: No file name is specified\n", getAppName());
- fprintf(stderr,usage);
- exit(1);
+ if (!filename[0])
+ {
+ fwprintf(stderr, L"%s: No file name is specified\n", getAppName());
+ // fwprintf(stderr, usage);
+ MessageBoxW(NULL, usage, NULL, MB_OK | MB_ICONINFORMATION);
+ exit(4);
}
- while(filename[0]) {
- reg_file = fopen(filename, "r");
- if (reg_file) {
- processRegLines(reg_file, doSetValue);
- fclose(reg_file);
- } else {
- perror("");
- fprintf(stderr,"%s: Can't open file \"%s\"\n", getAppName(), filename);
- exit(1);
+ LoadStringW(hInst, IDS_APP_TITLE, szTitle, COUNT_OF(szTitle));
+
+ while (filename[0])
+ {
+ /* Request import confirmation */
+ if (!silent)
+ {
+ LoadStringW(hInst, IDS_IMPORT_PROMPT, szText, COUNT_OF(szText));
+
+ if (InfoMessageBox(NULL, MB_YESNO | MB_ICONWARNING, szTitle, szText, filename) != IDYES)
+ goto cont;
+ }
+
+ fp = _wfopen(filename, L"r");
+ if (fp != NULL)
+ {
+ import_registry_file(fp);
+
+ /* Show successful import */
+ if (!silent)
+ {
+ LoadStringW(hInst, IDS_IMPORT_OK, szText, COUNT_OF(szText));
+ InfoMessageBox(NULL, MB_OK | MB_ICONINFORMATION, szTitle, szText, filename);
+ }
+
+ fclose(fp);
}
+ else
+ {
+ //LPSTR p = GetMultiByteString(filename);
+ //perror("");
+ fwprintf(stderr, L"%s: Can't open file \"%s\"\n", getAppName(), filename /*p*/);
+ //HeapFree(GetProcessHeap(), 0, p);
+
+ /* Error opening the file */
+ if (!silent)
+ {
+ LoadStringW(hInst, IDS_IMPORT_ERROR, szText, COUNT_OF(szText));
+ InfoMessageBox(NULL, MB_OK | MB_ICONERROR, szTitle, szText, filename);
+ }
+ }
+
+cont:
get_file_name(&s, filename);
}
break;
}
- case ACTION_DELETE: {
- CHAR reg_key_name[KEY_MAX_LEN];
+ case ACTION_DELETE:
+ {
+ WCHAR reg_key_name[KEY_MAX_LEN];
get_file_name(&s, reg_key_name);
- if (!reg_key_name[0]) {
- fprintf(stderr,"%s: No registry key is specified for removal\n",
- getAppName());
- fprintf(stderr,usage);
- exit(1);
+ if (!reg_key_name[0])
+ {
+ fwprintf(stderr, L"%s: No registry key is specified for removal\n", getAppName());
+ // fwprintf(stderr, usage);
+ MessageBoxW(NULL, usage, NULL, MB_OK | MB_ICONINFORMATION);
+ exit(6);
}
delete_registry_key(reg_key_name);
break;
}
- case ACTION_EXPORT: {
- CHAR filename[MAX_PATH];
- LPCTSTR pszFilename;
-#ifdef UNICODE
- WCHAR filename_wide[MAX_PATH];
-#endif
-
- filename[0] = '\0';
- get_file_name(&s, filename);
- if (!filename[0]) {
- fprintf(stderr,"%s: No file name is specified\n", getAppName());
- fprintf(stderr,usage);
- exit(1);
- }
-#ifdef UNICODE
- MultiByteToWideChar(CP_ACP, 0, filename, -1, filename_wide,
- sizeof(filename_wide) / sizeof(filename_wide[0]));
- pszFilename = filename_wide;
-#else
- pszFilename = filename;
-#endif
+ case ACTION_EXPORT:
+ {
+ WCHAR filename[MAX_PATH];
- if (s[0]) {
- CHAR reg_key_name[KEY_MAX_LEN];
+ filename[0] = L'\0';
+ get_file_name(&s, filename);
+ if (!filename[0])
+ {
+ fwprintf(stderr, L"%s: No file name is specified\n", getAppName());
+ // fwprintf(stderr, usage);
+ MessageBoxW(NULL, usage, NULL, MB_OK | MB_ICONINFORMATION);
+ exit(7);
+ }
+ if (s[0])
+ {
+ WCHAR reg_key_name[KEY_MAX_LEN];
get_file_name(&s, reg_key_name);
- export_registry_key(pszFilename, reg_key_name);
- } else {
- export_registry_key(pszFilename, NULL);
+ export_registry_key(filename, reg_key_name, REG_FORMAT_4);
+ }
+ else
+ {
+ export_registry_key(filename, NULL, REG_FORMAT_4);
}
break;
}
- default:
- fprintf(stderr,"%s: Unhandled action!\n", getAppName());
- exit(1);
- break;
+
+ default:
+ fwprintf(stderr, L"%s: Unhandled action!\n", getAppName());
+ exit(8);
+ break;
}
+
return TRUE;
}
+
+/**
+ * Process unknown switch.
+ *
+ * Params:
+ * chu - the switch character in upper-case.
+ * s - the command line string where s points to the switch character.
+ */
+static void error_unknown_switch(WCHAR chu, LPWSTR s)
+{
+ if (iswalpha(chu))
+ {
+ fwprintf(stderr, L"%s: Undefined switch /%c!\n", getAppName(), chu);
+ }
+ else
+ {
+ fwprintf(stderr, L"%s: Alphabetic character is expected after '%c' "
+ L"in switch specification\n", getAppName(), *(s - 1));
+ }
+ exit(1);
+}
+
+BOOL ProcessCmdLine(LPWSTR lpCmdLine)
+{
+ BOOL silent = FALSE;
+ REGEDIT_ACTION action = ACTION_UNDEF;
+ LPWSTR s = lpCmdLine; /* command line pointer */
+ WCHAR ch = *s; /* current character */
+
+ while (ch && ((ch == L'-') || (ch == L'/')))
+ {
+ WCHAR chu;
+ WCHAR ch2;
+
+ s++;
+ ch = *s;
+ ch2 = *(s + 1);
+ chu = towupper(ch);
+ if (!ch2 || iswspace(ch2))
+ {
+ if (chu == L'S')
+ {
+ /* Silence dialogs */
+ silent = TRUE;
+ }
+ else if (chu == L'V')
+ {
+ /* Ignore this switch */
+ }
+ else
+ {
+ switch (chu)
+ {
+ case L'D':
+ action = ACTION_DELETE;
+ break;
+ case L'E':
+ action = ACTION_EXPORT;
+ break;
+ case L'?':
+ //fwprintf(stderr, usage);
+ MessageBoxW(NULL, usage, NULL, MB_OK | MB_ICONINFORMATION);
+ exit(3);
+ break;
+ default:
+ error_unknown_switch(chu, s);
+ break;
+ }
+ }
+ s++;
+ }
+ else
+ {
+ if (ch2 == L':')
+ {
+ switch (chu)
+ {
+ case L'L':
+ /* fall through */
+ case L'R':
+ s += 2;
+ while (*s && !iswspace(*s))
+ {
+ s++;
+ }
+ break;
+ default:
+ error_unknown_switch(chu, s);
+ break;
+ }
+ }
+ else
+ {
+ /* this is a file name, starting from '/' */
+ s--;
+ break;
+ }
+ }
+ /* skip spaces to the next parameter */
+ ch = *s;
+ while (ch && iswspace(ch))
+ {
+ s++;
+ ch = *s;
+ }
+ }
+
+ if (*s && action == ACTION_UNDEF)
+ action = ACTION_ADD;
+
+ if (action != ACTION_UNDEF)
+ return PerformRegAction(action, s, silent);
+ else
+ return FALSE;
+}