[REGEDIT]
[reactos.git] / reactos / base / applications / regedit / regedit.c
index e157295..66ce69f 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * 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;
+}