regedit.c 6.75 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
/*
 * Windows regedit.exe registry editor implementation.
 *
 * Copyright 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
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
18
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 20
 */

21
#include <stdlib.h>
22
#include <windows.h>
23
#include <commctrl.h>
24
#include <shellapi.h>
25
#include "wine/debug.h"
26
#include "wine/heap.h"
27
#include "main.h"
28

29 30
WINE_DEFAULT_DEBUG_CHANNEL(regedit);

31
static void output_writeconsole(const WCHAR *str, DWORD wlen)
32 33 34 35 36 37 38 39 40 41 42 43 44
{
    DWORD count, ret;

    ret = WriteConsoleW(GetStdHandle(STD_OUTPUT_HANDLE), str, wlen, &count, NULL);
    if (!ret)
    {
        DWORD len;
        char  *msgA;

        /* WriteConsole() fails on Windows if its output is redirected. If this occurs,
         * we should call WriteFile() and assume the console encoding is still correct.
         */
        len = WideCharToMultiByte(GetConsoleOutputCP(), 0, str, wlen, NULL, 0, NULL, NULL);
45
        msgA = heap_xalloc(len);
46 47 48

        WideCharToMultiByte(GetConsoleOutputCP(), 0, str, wlen, msgA, len, NULL, NULL);
        WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), msgA, len, &count, FALSE);
49
        heap_free(msgA);
50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
    }
}

static void output_formatstring(const WCHAR *fmt, __ms_va_list va_args)
{
    WCHAR *str;
    DWORD len;

    SetLastError(NO_ERROR);
    len = FormatMessageW(FORMAT_MESSAGE_FROM_STRING|FORMAT_MESSAGE_ALLOCATE_BUFFER,
                         fmt, 0, 0, (WCHAR *)&str, 0, &va_args);
    if (len == 0 && GetLastError() != NO_ERROR)
    {
        WINE_FIXME("Could not format string: le=%u, fmt=%s\n", GetLastError(), wine_dbgstr_w(fmt));
        return;
    }
    output_writeconsole(str, len);
    LocalFree(str);
}

70
void WINAPIV output_message(unsigned int id, ...)
71 72 73 74
{
    WCHAR fmt[1536];
    __ms_va_list va_args;

75
    if (!LoadStringW(GetModuleHandleW(NULL), id, fmt, ARRAY_SIZE(fmt)))
76 77 78 79 80 81 82 83
    {
        WINE_FIXME("LoadString failed with %d\n", GetLastError());
        return;
    }
    __ms_va_start(va_args, id);
    output_formatstring(fmt, va_args);
    __ms_va_end(va_args);
}
84

85
void WINAPIV error_exit(unsigned int id, ...)
86 87 88 89
{
    WCHAR fmt[1536];
    __ms_va_list va_args;

90
    if (!LoadStringW(GetModuleHandleW(NULL), id, fmt, ARRAY_SIZE(fmt)))
91 92 93 94 95 96 97 98 99 100 101
    {
        WINE_FIXME("LoadString failed with %u\n", GetLastError());
        return;
    }
    __ms_va_start(va_args, id);
    output_formatstring(fmt, va_args);
    __ms_va_end(va_args);

    exit(0); /* regedit.exe always terminates with error code zero */
}

102
typedef enum {
103
    ACTION_ADD, ACTION_EXPORT, ACTION_DELETE
104 105
} REGEDIT_ACTION;

106
static void PerformRegAction(REGEDIT_ACTION action, WCHAR **argv, int *i)
107
{
108 109
    switch (action) {
    case ACTION_ADD: {
110 111
            WCHAR *filename = argv[*i];
            WCHAR hyphen[] = {'-',0};
112
            WCHAR *realname = NULL;
113
            FILE *reg_file;
114

115
            if (!lstrcmpW(filename, hyphen))
116 117 118 119 120
                reg_file = stdin;
            else
            {
                int size;
                WCHAR rb_mode[] = {'r','b',0};
121

122 123
                size = SearchPathW(NULL, filename, NULL, 0, NULL, NULL);
                if (size > 0)
124
                {
125
                    realname = heap_xalloc(size * sizeof(WCHAR));
126
                    size = SearchPathW(NULL, filename, NULL, size, realname, NULL);
127
                }
128
                if (size == 0)
129
                {
130
                    output_message(STRING_FILE_NOT_FOUND, filename);
131
                    heap_free(realname);
132
                    return;
133 134 135 136 137 138
                }
                reg_file = _wfopen(realname, rb_mode);
                if (reg_file == NULL)
                {
                    WCHAR regedit[] = {'r','e','g','e','d','i','t',0};
                    _wperror(regedit);
139
                    output_message(STRING_CANNOT_OPEN_FILE, filename);
140
                    heap_free(realname);
141
                    return;
142
                }
143 144 145 146
            }
            import_registry_file(reg_file);
            if (realname)
            {
147
                heap_free(realname);
148
                fclose(reg_file);
149 150 151
            }
            break;
        }
152 153
    case ACTION_DELETE:
            delete_registry_key(argv[*i]);
154 155
            break;
    case ACTION_EXPORT: {
156 157
            WCHAR *filename = argv[*i];
            WCHAR *key_name = argv[++(*i)];
158

159
            if (key_name && *key_name)
160
                export_registry_key(filename, key_name, REG_FORMAT_5);
161
            else
162
                export_registry_key(filename, NULL, REG_FORMAT_5);
163
            break;
164 165
        }
    default:
166
        error_exit(STRING_UNHANDLED_ACTION);
167 168 169
        break;
    }
}
170

171
BOOL ProcessCmdLine(WCHAR *cmdline)
172
{
173 174
    WCHAR **argv;
    int argc, i;
175
    REGEDIT_ACTION action = ACTION_ADD;
176

177
    argv = CommandLineToArgvW(cmdline, &argc);
178

179 180
    if (!argv)
        return FALSE;
181

182
    if (argc == 1)
183
    {
184 185
        LocalFree(argv);
        return FALSE;
186 187
    }

188
    for (i = 1; i < argc; i++)
189 190 191 192 193 194 195 196 197 198
    {
        if (argv[i][0] != '/' && argv[i][0] != '-')
            break; /* No flags specified. */

        if (!argv[i][1] && argv[i][0] == '-')
            break; /* '-' is a filename. It indicates we should use stdin. */

        if (argv[i][1] && argv[i][2] && argv[i][2] != ':')
            break; /* This is a file path beginning with '/'. */

199
        switch (towupper(argv[i][1]))
200
        {
201
        case '?':
202
            error_exit(STRING_USAGE);
203
            break;
204 205 206 207 208 209
        case 'D':
            action = ACTION_DELETE;
            break;
        case 'E':
            action = ACTION_EXPORT;
            break;
210
        case 'C':
211
        case 'L':
212
        case 'M':
213 214 215 216 217 218 219 220
        case 'R':
            /* unhandled */;
            break;
        case 'S':
        case 'V':
            /* ignored */;
            break;
        default:
221
            output_message(STRING_INVALID_SWITCH, argv[i]);
222
            error_exit(STRING_HELP);
223 224 225
        }
    }

226 227 228 229 230 231
    if (i == argc)
    {
        switch (action)
        {
        case ACTION_ADD:
        case ACTION_EXPORT:
232
            output_message(STRING_NO_FILENAME);
233 234
            break;
        case ACTION_DELETE:
235
            output_message(STRING_NO_REG_KEY);
236 237
            break;
        }
238
        error_exit(STRING_HELP);
239 240
    }

241 242
    for (; i < argc; i++)
        PerformRegAction(action, argv, &i);
243

244
    LocalFree(argv);
245

246
    return TRUE;
247
}